3

多年来,我一直在使用以下逻辑在夜间批处理作业中解析 csv 文件,没有问题。无论如何,我正在对应用程序进行全面重写,现在我想知道使用 opencsv 之类的东西是否会带来任何性能/质量提升?我没有使用其他图书馆的经验,所以我希望其他有经验的人可以加入。

while ((line = br.readLine()) != null) {
    String[] items = line.split(",");


        for (int i = 0; i < items.length; ++i) {
            // Remove extra quote
            if (items[i].length > 2) {
                items[i] = items[i].replaceAll("\"", "");
            }

            // Replace blank items with nulls
            if (items[i].matches("^\\s*$")) {
                items[i] = null;
            }

        }

        String item0 = item[0];
        String item1 = item[1];
}
4

3 回答 3

4

您不会获得任何性能,但库将帮助您处理嵌入逗号的字段。微软使用双引号而不是转义逗号的令人讨厌的解决方案是手工处理的痛苦,而 opencsv 将为您处理所有这些。

于 2013-10-26T04:52:21.383 回答
4

chrylis给出的答案是正确的,您可能不会获得性能,但是 opencsv 会为您处理所有情况。
但是,如果您真的担心性能,那么在您的代码中进行一些调整可以帮助您提高性能,
在分析 String.Split 的代码之后

    public String[] split(String regex) {
       return split(regex, 0);
    }
    public String[] split(String regex, int limit) {
           return Pattern.compile(regex).split(this, limit);
    }

对于您的每个字符串,都会编译一个新模式,Pattern.compile 的代码是

public static Pattern compile(String regex, int flags) {
     return new Pattern(regex, flags);
 }

上面创建 Pattern 对象的代码再次重复,

items[i].matches("^\\s*$")

因此,如果您的文件有数百万行,那么创建数百万个 Pattern 对象可能会产生开销,因此您可以将代码更改为,

    Pattern pat = Pattern.compile(","); 
    Pattern regexPattern = Pattern.compile("^\\s*$");       
    while ((line = br.readLine()) != null) 
    {
        String[] items = pat.split(line, 0);
        for (int i = 0; i < items.length; ++i) 
        {           
            if (items[i] != null && items.length > 2) // I think it should be items[i].length() > 2 
            { //We can also remove this null check as splitted strings will never be null
                items[i] = items[i].replaceAll("\"", "");
            }               
            if (regexPattern.matcher(items[i]) .matches()) {
                items[i] = null;
            }
        }           
    }

性能提升在小文件中不可见,但对于大文件,如果对数百万个文件执行相同的代码,您将看到显着的性能提升。

于 2013-10-26T05:23:38.123 回答
0

要添加到您的选项,请考虑使用 Jackson CsvMapper。

我在 macbook pro 上使用 jackson CsvMapper 在 12 分钟内从大约 4k 文件中解析出 3600 万行。那是在某些地方使用它直接映射到 POJO,并使用它在其他地方每行读取 Object[],并应用大量辅助处理来规范化输入。

它也很容易使用:

作为对象[]

    CsvMapper mapper = new CsvMapper();
    mapper.enable(CsvParser.Feature.WRAP_AS_ARRAY);
    File csvFile = new File("input.csv"); // or from String, URL etc
    MappingIterator<Object[]> it = mapper.reader(Object[].class).readValues(csvFile);

作为 POJO

    public class CSVPerson{
      public String firstname;
      public String lastname;
      //etc
    }

    CsvMapper mapper = new CsvMapper();
    CsvSchema schema = CsvSchema.emptySchema().withHeader().withColumnSeparator(delimiter);
    MappingIterator<CSVPerson> it = = mapper.reader(CSVPerson).with(schema).readValues(input);
    while (it.hasNext()){
      CSVPerson row = it.next();
    }

我一直在歌颂这个图书馆,它很棒。它也非常灵活。

于 2013-10-28T13:59:36.097 回答