6

我有一个 37 列的 CSV 文件,我正在使用 Apache Commons CSV 1.2 在 Java 中解析它。我的设置代码如下:

//initialize FileReader object
FileReader fileReader = new FileReader(file);

//intialize CSVFormat object
CSVFormat csvFileFormat = CSVFormat.DEFAULT.withHeader(FILE_HEADER_MAPPING);

//initialize CSVParser object
CSVParser csvFileParser = new CSVParser(fileReader, csvFileFormat);

//Get a list of CSV file records
List<CSVRecord> csvRecords = csvFileParser.getRecords();

// process accordingly

我的问题是,当我将要处理的 CSV 复制到目标目录并运行解析程序时,出现以下错误:

Exception in thread "main" java.lang.IllegalArgumentException: Index for header 'Title' is 7 but CSVRecord only has 6 values!
        at org.apache.commons.csv.CSVRecord.get(CSVRecord.java:110)
        at launcher.QualysImport.createQualysRecords(Unknown Source)
        at launcher.QualysImport.importQualysRecords(Unknown Source)
        at launcher.Main.main(Unknown Source)

但是,如果我将文件复制到我的目标目录,打开并保存它,然后再次尝试该程序,它可以工作。打开并保存 CSV 会在最后添加所需的逗号,这样我的程序就不会因为没有足够的标题来读取而感到沮丧。

对于上下文,这是保存之前/之后的示例行:

之前(失败):“数据”、“数据”、“数据”、“数据”

之后(工作):“数据”,“数据”,,,,“数据”,,“数据”,,,,,,

所以我的问题是:为什么打开并保存 CSV 格式会发生变化?我没有更改任何值或编码,保存时 MS-DOS 或常规 .csv 格式的行为相同。另外,我在测试中使用 Excel 来复制/打开/保存。

我需要使用一些编码或格式设置吗?我可以以编程方式解决这个问题吗?

提前致谢!

编辑#1:

对于其他上下文,当我第一次查看原始文件中的空行时,它只有新行 ^M 字符,如下所示:

^M

在 Excel 中打开并保存后,我的 37 个空字段看起来像这样:

,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,^M

这是 Windows 编码差异吗?

4

3 回答 3

2

也许这是首先生成文件的兼容性问题。似乎 Excel 接受一个空行作为每列中包含空字符串的有效行,列数与其他行匹配。然后它根据 CSV 约定使用列分隔符保存它。(^M 是回车符;在 Microsoft 系统上,它位于文本文件中行尾的换行符之前)

也许你可以通过创建你自己的Reader子类来处理它,它位于 FileReader 和 CSVParser 之间。您的阅读器将读取一行,如果它是空白的,则返回带有正确逗号数的行。否则,只需按原样返回该行。

例如:

class MyCSVCompatibilityReader extends BufferedReader
    {
    private final BufferedReader delegate;

    public MyCSVCompatibilityReader(final FileReader fileReader)
        {
        this.delegate = new BufferedReader(fileReader);
        }

    @Override
    public String readLine()
        {
        final String line = this.delegate.readLine();
        if ("".equals(line.trim())
            { return ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"; }
        else
            { return line; }
        }
    }

实现接口时,还有很多其他细节需要正确实现。您需要传递对所有其他方法(关闭、就绪、重置、跳过等)的调用,并确保各种read()方法中的每一个都能正常工作。如果文件很容易放入内存,则可能更容易读取文件并将固定版本写入新的StringWriter ,然后为 CSVParser创建一个StringReader 。

于 2016-04-15T21:05:56.223 回答
-1

也许试试这个:为给定的文件创建一个解析器。解析(文件文件、Charset charset、CSVFormat 格式)

//导入导入java.nio.charset.StandardCharsets; //标准字符集.UTF_8

注意:此方法使用 FileReader.FileReader(java.io.File) 在内部创建一个 FileReader,而这又依赖于执行代码的 JVM 的默认编码。

于 2016-04-15T17:40:24.270 回答
-1

或者也许尝试使用AllowMissingColumnNames?

//intialize CSVFormat object 
CSVFormat csvFileFormat = CSVFormat.DEFAULT.withHeader(FILE_HEADER_MAPPING).withAllowMissingColumnNames();
于 2016-04-15T18:10:42.247 回答