【发布时间】:2022-12-15 15:48:56
【问题描述】:
我正在编写代码来处理 tar.gz 文件列表,其中有多个 csv 文件。我遇到了以下错误
com.opencsv.exceptions.CsvMalformedLineException: Unterminated quoted field at end of CSV line. Beginning of lost text: [,,,,,,
]
at com.opencsv.CSVReader.primeNextRecord(CSVReader.java:245)
at com.opencsv.CSVReader.flexibleRead(CSVReader.java:598)
at com.opencsv.CSVReader.readNext(CSVReader.java:204)
at uk.ac.shef.inf.analysis.Test.readAllLines(Test.java:64)
at uk.ac.shef.inf.analysis.Test.main(Test.java:42)
导致这个问题的代码在下面的 B 行。
public class Test {
public static void main(String[] args) {
try {
Path source = Paths.get("/home/xxxx/Work/data/amazon/labelled/small/Books_5.json.1.tar.gz");
InputStream fi = Files.newInputStream(source);
BufferedInputStream bi = new BufferedInputStream(fi);
GzipCompressorInputStream gzi = new GzipCompressorInputStream(bi);
TarArchiveInputStream ti = new TarArchiveInputStream(gzi);
CSVParser parser = new CSVParserBuilder().withStrictQuotes(true)
.withQuoteChar('"').withSeparator(',').
.withEscapeChar('|'). // Line A
build();
BufferedReader br = null;
ArchiveEntry entry;
entry = ti.getNextEntry();
while (entry != null) {
br = new BufferedReader(new InputStreamReader(ti)); // Read directly from tarInput
System.out.format("\n%s\t\t > %s", new Date(), entry.getName());
try{
CSVReader reader = new CSVReaderBuilder(br).withCSVParser(parser)
.build();
List<String[]> r = readAllLines(reader);
} catch (Exception ioe){
ioe.printStackTrace();
}
System.out.println(entry.getName());
entry=ti.getNextEntry(); // Line B
}
}catch (Exception e){
e.printStackTrace();
}
}
private static List<String[]> readAllLines(CSVReader reader) {
List<String[]> out = new ArrayList<>();
int line=0;
try{
String[] lineInArray = reader.readNext();
while(lineInArray!=null) {
//System.out.println(Arrays.asList(lineInArray));
out.add(lineInArray);
line++;
lineInArray=reader.readNext();
}
}catch (Exception e){
System.out.println(line);
e.printStackTrace();
}
System.out.println(out.size());
return out;
}
}
我还在此处附上导致此问题的 csv 文件中实际行的屏幕截图,请查看第 5213 行。我还在此处包含一个测试 tar.gz 文件:https://drive.google.com/file/d/1qHfWiJItnE19-BFdbQ3s3Gek__VkoUqk/view?usp=sharing
调试时,我有一些问题。
- 我认为问题出在数据文件(上面第 5213 行)中的 \ 字符,它是 Java 中的转义字符。我通过在上面的代码中添加行 A 来验证这个想法,并且它有效。但是,显然我不想对此进行硬编码,因为数据中可能有其他字符导致同样的问题。所以我的问题 1 是:有没有告诉 Java 忽略转义字符?类似于
withEscapeChar('|')的反义词?更新:答案是使用'\0',感谢下面的第一条评论。 - 调试时,我注意到我的程序在遇到上述异常后立即停止处理 tar.gz 文件中的下一个 .csv 文件。为了解释我的意思,在上面链接中包含的 tar.gz 文件中,有两个 csvs:_10.csv 和 _110.csv。有问题的行在 _10.csv 中。当我的程序遇到该行时,会抛出一个异常,程序会转到下一个文件 _110.csv (
entry=ti.getNextEntry();)。这个文件实际上没问题,但是应该读取下一个 csv 文件的方法readAllLines将在第一行立即抛出相同的异常。我认为我的代码不正确,尤其是while循环:我怀疑输入流仍然停留在导致异常的先前位置。但我不知道如何解决这个问题。请帮忙?
【问题讨论】:
-
您是否尝试过 similar question 中推荐的任何其他转义字符,例如 NUL char
'\0'? -
您还必须确定数据提供者使用什么字符来转义字符串中的嵌入引号。处理 CSV 中嵌入双引号的标准方法是连续使用两个双引号字符,即
"String containing "" a double quote"。这在技术上不是与 Java 反斜杠相同方式的转义字符,因为它仅适用于双引号字符,而不是一般转义。 -
大多数推荐
RFC4180Parser来解决转义反斜杠问题,如 DZone 中所述:OpenCSV: Properly Handling Backslashes。 -
@hc_dev 我刚刚试过了,可以用,谢谢!我更新了我的帖子。仍然想知道第二个问题的答案,因为我认为我的 while 循环是错误的......
-
看起来您没有关闭(或使用 try-with-resources for )BufferedReader 和/或其他输入流。在更改“父”资源管理器的状态之前,您可能需要在 catch 子句中对该阅读器进行一些维护
ti