【问题标题】:Why is CSVParser is reading the next CSVRecord为什么 CSVParser 正在读取下一个 CSVRecord
【发布时间】:2018-09-26 08:26:43
【问题描述】:

使用org.apache.commons.csv.CSVParser 我有一个奇怪的行为。

我正在尝试逐行读取由 ; 分隔的 csv 文件,但我的解析器由于未知原因正在跳过行。

这是我的代码:

public static void main(String[] args) {
    try (
        File file = new File("myFile.csv");
        Reader reader = new BufferedReader(new FileReader(file));
        CSVParser parser = new CSVParser(reader, CSVFormat.DEFAULT.withDelimiter(';'));
    ) {
        if (!parser.iterator().hasNext()) {
            throw new RuntimeException("The file is empty.");
        }
        while(parser.hasNext()) { //<----- This skip a line! 
            console.log(parser.iterator().next().get(0).trim());
        }
    }
}

所以我的控制台看起来像:

line2
line4
line6
line8
line10
line12

等等……

所以我的问题是 CSVParser 在 parser.hasNext() 上跳过了一行,它不应该。

我的代码错了吗? 我很确定如果我用 ArrayList 替换解析器,迭代器会按预期工作...... 这是一个已知的错误? 如果是的话,你们能指出解决方法或更好的图书馆吗?

【问题讨论】:

  • 请注意,使用 foreach 循环可能更具可读性:for (CSVRecord csvRecord : parser)

标签: java apache-commons-csv


【解决方案1】:

你遇到的问题是每次迭代调用iterator(),它返回一个新的Iterator

事情变得奇怪了,因为迭代器有一个 current 字段存储当前记录,当然新迭代器的当前记录是 null

在这种情况下,它会从 CSVParser (source code) 调用 getNextRecord(),从而跳过一行。

如果你想坚持使用迭代器,只需重复使用相同的实例:

Iterator<CSVRecord> iterator = parser.iterator();

while(iterator.hasNext()) { 
    console.log(iterator.next().get(0).trim());
}

【讨论】:

  • 是的,这是有效的,谢谢!这是迭代器的正常行为吗?或者这只是一个错误的实现?
  • 我不知道,但是您没有任何理由调用多个迭代器来迭代单个集合。 cmets 中的 foreach 循环 for (CSVRecord csvRecord : parser) 只是在后台执行此操作,调用迭代器并使用它进行迭代。这也是我们更喜欢使用 foreach 语句的原因。
  • 不能使用 foreach 循环,因为我复制的代码在 SpringBatch 的 ItemReader 中被拆分,所以我一次只需要返回一个元素,并且“循环”由 SpringBatch 处理
【解决方案2】:

好吧,默认情况下,解析器将第一行视为标题(列定义),因此在返回的记录中会跳过它。要包含此行,您必须使用withSkipHeaderRecord 相应地准备格式。

编辑: 对不起,我读得太快了。我以为只有第一行被跳过了。

【讨论】:

  • 好的,但它没有解释为什么它会跳过每一行。如果它确实只跳过了一行,我会理解,但它会跳过每一行!
猜你喜欢
  • 2016-04-16
  • 1970-01-01
  • 2019-07-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-22
  • 2023-02-13
  • 1970-01-01
相关资源
最近更新 更多