自定义 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);
}
我必须读取一个 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);
}