多年来,我一直在夜间批处理作业中使用以下逻辑解析 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];
}
您不会获得任何性能,但库将帮助您处理嵌入逗号的字段。Microsoft使用双引号而不是转义逗号的令人讨厌的解决方案是手工处理的痛苦,OpenCSV 将为您处理所有这些。
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;
}
}
}
性能提升在小文件中不可见,但对于大文件,如果对数百万个文件执行相同的代码,您将看到显着的性能改进。
要添加到您的选项中,请考虑 Jackson CsvMapper。
我在 12 分钟内使用 macbook Pro 上的 jackson CsvMapper 解析了大约 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();
}
我总是赞美这个图书馆,它很棒。 它也非常灵活。