【问题标题】:How do you parse a difficult .txt file?你如何解析一个困难的 .txt 文件?
【发布时间】:2014-03-28 12:28:12
【问题描述】:

我对 java 还很陌生,一直在尝试读取一个非常困难的 .txt 文件并将其输入到我的 MySQL 数据库中。

对我来说,文件有一些非常奇怪的分隔规则。定界似乎都是逗号,但其他部分没有任何意义。这里有几个例子:

" "," "," "," "," "

" ",,,,,,," "

" ",0.00," "

" ",," ",," ",," "

我所知道的是所有包含字母的字段都是正常的,"text", 格式。

所有只有数字的列都将遵循这种格式:,0.00, 除了第一列遵循正常格式"123456789",

那么任何没有数据的东西都会在,,," ",之间交替

我已经能够让程序使用 java.sql.Statement 正确读取,但我需要它才能使用 java.sql.PreparedStatement

我可以让它只选择几列,但我需要它来处理 100 多列,并且某些字段包含逗号,例如"Some Company, LLC"

这是我目前拥有的代码,但我不知道下一步该去哪里。

import java.io.BufferedReader;
import java.io.FileReader;
import java.sql.*;


public class AccountTest {

  public static void main(String[] args) throws Exception {


        //Declare DB settings
    String dbName = "jdbc:mysql://localhost:3306/local";
    String userName = "root";
    String password = "";
    String fileName = "file.txt";
    String psQuery = "insert into accounttest"
                     + "(account,account_name,address_1,address_2,address_3) values"
                     + "(?,?,?,?,?)";
    Connection connect = null;
    PreparedStatement statement = null;
    String account = null;
    String accountName = null;
    String address1 = null;
    String address2 =null;
    String address3 = null;


        //Load JDBC Driver
    try {
        Class.forName("com.mysql.jdbc.Driver");
    }
    catch (ClassNotFoundException e) {
        System.out.println("JDBC driver not found.");
        e.printStackTrace();
        return;
    }


        //Attempt connection
    try {
    connect = DriverManager.getConnection(dbName,userName,password);
    }
    catch (SQLException e) {
        System.out.println("E1: Connection Failed.");
        e.printStackTrace();
        return;         
    }


        //Verify connection
    if (connect != null) {
        System.out.println("Connection successful.");
    }   
    else {
        System.out.println("E2: Connection Failed.");
    }


      BufferedReader bReader = new BufferedReader(new FileReader(fileName));
        String line;

        //import file into mysql DB
    try {

        //Looping the read block until all lines in the file are read.
    while ((line = bReader.readLine()) != null) {

            //Splitting the content of comma delimited file
        String data[] = line.split("\",\"");

            //Renaming array items for ease of use
        account = data[0];
        accountName = data[1];
        address1 = data[2];
        address2 = data[3];
        address3 = data[4];

            // removing double quotes so they do not get put into the db
        account = account.replaceAll("\"", "");
        accountName = accountName.replaceAll("\"", "");
        address1 = address1.replaceAll("\"", "");
        address2 = address2.replaceAll("\"", "");
        address3 = address3.replaceAll("\"", "");

            //putting data into database
        statement = connect.prepareStatement(psQuery);
        statement.setString(1, account);
        statement.setString(2, accountName);
        statement.setString(3, address1);
        statement.setString(4, address2);
        statement.setString(5, address3);
        statement.executeUpdate();
    }
    }
    catch (Exception e) {
        e.printStackTrace();
        statement = null;
    }
    finally {
        bReader.close();
    }
}   
}

对不起,如果它的格式不正确,我还在学习,在困惑了几天试图弄清楚这一点之后,我没有费心让它看起来不错。

我的问题是这样一个混乱的文件是否可能发生这样的事情?如果是这样,我该如何去做呢?另外,我对准备好的语句并不完全熟悉,我必须声明每一列还是有更简单的方法?

提前感谢您的帮助。

编辑:为了澄清我需要将 txt 文件上传到 MySQL 数据库,我需要一种方法来读取和拆分(除非有更好的方法)基于",",,,,,0.00, 并仍然将字段 Some Company, LLC 中包含逗号的字段保持在一起。我需要使用 100 多列来执行此操作,并且文件从 3000 到 6000 行不等。需要将其作为准备好的语句执行。我不确定这是否可行,但我感谢任何人就此事提出的任何意见。

EDIT2 : 多亏了 rpc1,我才能够弄清楚如何整理凌乱的文件。而不是String data[] = line.split("\",\""); 我使用String data[] = line.split(",(?=([^\"]*\"[^\"]*\")*[^\"]*$)"); 我仍然必须写出每个变量以将其链接到data[] 然后为每列写出每个statement.setString 以及为每列写replaceALL("\"", ""); 但我得到了它有效,我找不到另一种使用准备好的语句的方法。感谢您的所有帮助!

【问题讨论】:

  • 您使用 PreparedStatement 的方式对我来说似乎相当不错。您甚至可以使用 executeUpdate(),这是正确的,而许多初学者在 INSERT/UPDATE/DELETE 语句中使用 executeQuery() 是错误的。关于文件,如果它没有明确定义的格式,那么使用它将非常困难(甚至不可能)。
  • 谢谢。我花了两天时间阅读 stackoverflow 问题并意识到什么是好习惯,什么不是好习惯。我知道这适用于带有定义文件分隔方式的查询的常规语句。我不明白它是如何正确阅读的,但确实如此。
  • 您在处理文件的第 3 行时没有收到IndexOutOfBoundsException 吗?它应该被分割成一个 3 长度的数组,调用 data[3] 应该会抛出异常。
  • 我不明白为什么需要手动解析 csv 文件,您可以使用 JavaCSV 之类的第 3 方 csv 解析器。并且请不要回应我的老板/讲师告诉我的
  • 它不是一个csv文件,不能更改服务器来添加第三方应用程序。公司规定。我可以运行服务器,但我不知道可以添加什么,这就是为什么我必须这样做。

标签: java mysql sql jdbc


【解决方案1】:

你可以循环 例如:

    String psQuery = "insert into accounttest"
                         + "(account,account_name,address_1,address_2,address_3,..,adrress_n) values"
                         + "(?,?,?,?,?,?,..,?)";  //you have to put m=n+2 values

.....

     //you can change separator 
            String data[] = line.replace("\",\"",";").replace("\"","").split(";");

              for(int i=0;i<m;i++)
              { 
                  if(i<data.length) //if index smaller then array siz
                      statement.setString(i+1, data[i]);
                  else
                      statement.setString(i+1, ""); //put null
              }
              statement.executeUpdate();

附:如果您的 csv 文件较大,请使用批量插入 (addBatch()) 并使用 Pattern 分割字符串

Pattern p = Pattern.compile(";",""); 
p.split(st);

编辑 试试这个拆分功能

private static Pattern pSplit = Pattern.compile("[^,\"']+|\"([^\"]*)\"|'([^']*)'"); //set pattern as global var
private static Pattern pReplace = Pattern.compile("\"");
public static Object[] split(String st)
{
   List<String> list = new ArrayList<String>();
   Matcher m = pSplit.matcher(st);
   while (m.find())
   list.add( pReplace.matcher(m.group(0)).replaceAll("")); // Add .replace("\"", "") to remove surrounding quotes.
   return list.toArray();
}

例如 输入字符串:st="\"1212\",\"LL C ,DDD \",\"CA, SPRINGFIELD\",232.11,3232.00"; 拆分 5 项数组:

1212
LL C ,DDD
CA, SPRINGFIELD
232.11
3232.00

EDIT2

this example solves all your problems (even empty values)


private static Pattern pSplit = Pattern.compile(",(?=([^\"]*\"[^\"]*\")*[^\"]*$)");
public static String[] split2(String st)
{
    String[] tokens = pSplit.split(st);       
    return tokens;
}

【讨论】:

  • 对不起,我的措辞不正确。这是一段很好的代码,我稍后会记住。我目前需要的是找出一种正确拆分文件的方法,具体取决于文件的该部分是如何分隔的。因此,如果遇到",",它可以从中拆分,但也可以从,0.00, 拆分以及从,,,, 分隔我不知道这是否是准备好的语句的可能性。
  • 哦,我有你的问题...并且有一个问题:每行中的字段数是恒定的吗?如果是,我知道如何解决您的问题
  • 是的,数字是字段是恒定的,只是获取该数字的方式很尴尬并且每行都不同。我很想听听你有什么。
  • 但是空数据有问题,你可以自己编辑pattern来解决这个问题,或者替换空值例如replace(",,",",\"\","跨度>
  • 可能需要我一点时间才能弄清楚。我的 IDE 给了我一些奇怪的错误,例如:Syntax error on token "(", ; expected Syntax error on token ")", ; expected on split2(String st) 感谢您的回复,我将努力实现此功能,看看是否可以解决。
【解决方案2】:

我能够通过这一点代码找出我遇到的两个问题。再次感谢您的所有帮助!

for (String line = bReader.readLine(); line != null; line = bReader.readLine()) {   

          //Splitting the content of comma delimited file
    String data[] = line.split(",(?=([^\"]*\"[^\"]*\")*[^\"]*$)");

         //Iterating through the file and updating the table.
    statement = connect.prepareStatement(psQuery);
    for (int i =0; i < data.length;i++) {
        temp =  data[i];
        temp = temp.replaceAll("\"", "");
        statement.setString(i+1, temp);
    }
    statement.executeUpdate();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-14
    相关资源
    最近更新 更多