自定义 CSVFormat.RFC4180

Customize CSVFormat.RFC4180

我必须读取一个 csv 文件。该文件可以包含任何分隔符,并且可以用“”\”或不包含。该文件还应该根据 RFC4180 进行解析。(我知道在 RFC4180 中,分隔符是一个“,”,但用户也应该能够阅读例如,由“|”分隔的文件)。

public List<List<String>> readFileAsListOfList(File file, String delimiter, String lineEnding, String enclosure) throws Exception {
        if (!file.exists()) {
            throw new Exception("File doesn't exist.");
        }
        if (!file.isFile()) {
            throw new Exception("File must be a file.");
        }

        List<List<String>> fileContent = new ArrayList<>();
        CSVFormat csvFormat = CSVFormat.RFC4180.withDelimiter(delimiter.charAt(0)).withEscape(lineEnding.charAt(0));
        if (StringUtils.isNotEmpty(enclosure)) {
            csvFormat.withQuote(enclosure.charAt(0));
        } else {
            csvFormat.withQuote(null);
        }
        System.out.println(csvFormat);
        List<String> lineContent = new ArrayList<>();
        for (CSVRecord rec : csvFormat.parse(new FileReader(file))) {
            for (String field : rec) {
                lineContent.add(field);
            }
            fileContent.add(lineContent);
        }
        return fileContent;
    }

如果我现在遇到文件未包含在内的情况,并且我有这样一行

aaa|bbb|"|ccc

我收到以下错误:

Exception in thread "main" java.lang.IllegalStateException: IOException reading next record: java.io.IOException: (startline 120707) EOF reached before encapsulated token finished at org.apache.commons.csv.CSVParser.getNextRecord(CSVParser.java:530) at org.apache.commons.csv.CSVParser.hasNext(CSVParser.java:540) at com.ids.dam.pim.validation.CSVFileReaderApache.readFileAsListOfList(CSVFileReaderApache.java:61) at com.ids.dam.pim.validation.CSVFileReaderApache.main(CSVFileReaderApache.java:78) Caused by: java.io.IOException: (startline 120707) EOF reached before encapsulated token finished at org.apache.commons.csv.Lexer.parseEncapsulatedToken(Lexer.java:288) at org.apache.commons.csv.Lexer.nextToken(Lexer.java:158) at org.apache.commons.csv.CSVParser.nextRecord(CSVParser.java:586) at org.apache.commons.csv.CSVParser.getNextRecord(CSVParser.java:527) ... 3 more

我认为这是因为我的 CSVFormat 仍然包含双引号作为附件,因为这是 RFC4180 中的默认设置。

打印格式如下:

Delimiter=<|> Escape=<L> QuoteChar=<"> RecordSeparator=<
> SkipHeaderRecord:false

对我来说,这意味着我可以用 CSVFormat.RFC4180.withDelimiter(delimiter.charAt(0)... 覆盖默认分隔符,但我不能将围栏设置为 null

有没有办法在仍然使用 RFC4180 的同时将附件设置为空?

CSV 中的引号始终是可选的,引号字符可以作为分隔符选择。如果您知道您的文件使用 | 定界符且没有引号,则应该以这种方式构建 CSVFormat。请注意,withOption(...) 不会将选项应用于当前的 csv 格式,而是 returns 与原始格式相同但设置了选项的现在格式。来自 Apache CSVFormat javadoc

public CSVFormat withQuoteMode(QuoteMode quoteModePolicy)

Returns a new CSVFormat with the output quote policy of the format set to the specified value.
...

Returns: A new CSVFormat that is equal to this but with the specified quote policy

你应该使用:

    CSVFormat csvFormat = CSVFormat.RFC4180.withDelimiter(delimiter.charAt(0))
            .withEscape(lineEnding.charAt(0));
    if (StringUtils.isNotEmpty(enclosure)) {
        csvFormat = csvFormat.withQuote(enclosure.charAt(0));
    } else {
        csvFormat = csvFormat.withQuoteMode(NONE);
    }