为什么 BufferedReader readLine 读取过去的 EOF
Why is BufferedReader readLine reading past EOF
我有一个非常大的文件 (~6GB),其中包含由 \r\n 分隔的固定宽度文本,因此我使用缓冲 reader 逐行读取。这个过程可以被中断或停止,如果是,它会使用检查点 "lastProcessedLineNbr" 快进到正确的位置以继续读取。这就是 reader 的初始化方式。
private void initializeBufferedReader(Integer lastProcessedLineNbr) throws IOException {
reader = new BufferedReader(new InputStreamReader(getInputStream(), "UTF-8"));
if(lastProcessedLineNbr==null){lastProcessedLineNbr=0;}
for(int i=0; i<lastProcessedLineNbr;i++){
reader.readLine();
}
currentLineNumber = lastProcessedLineNbr;
}
这似乎工作正常,我用这种方法读取和处理数据:
public Object readItem() throws Exception {
if((currentLine = reader.readLine())==null){
return null;
}
currentLineNumber++;
return parse(currentLine);
}
再一次,一切正常,直到我到达文档的最后一行。后一种方法中的 readLine() 抛出错误:
17:06:49,980 ERROR [org.jberet] (Batch Thread - 1) JBERET000007: Failed to run job ProdFileRead, parse, org.jberet.job.model.Chunk@3965dcc8: java.lang.OutOfMemoryError: Requested array size exceeds VM limit
at java.util.Arrays.copyOf(Arrays.java:3332)
at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:137)
at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:121)
at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:569)
at java.lang.StringBuffer.append(StringBuffer.java:369)
at java.io.BufferedReader.readLine(BufferedReader.java:370)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at com.rational.batch.reader.TextLineReader.readItem(TextLineReader.java:55)
奇怪的是,它似乎正在读取文件末尾并分配如此多 space 以致内存不足。我尝试使用 Cygwin 和 "tail file.txt" 查看文件的内容,在控制台中它给了我预期的 10 行。但是当我这样做时 "tail file.txt > output.txt" output.txt 最终变成了 1.8GB,比我预期的 10 行大得多。所以看起来 Cygwin 也在做同样的事情。据我所知,没有特殊的 EOF 字符。它只是数据的最后一个字节,并且突然结束。
任何人都知道我如何让它工作?我在想我可以求助于计算读取的字节数,直到我得到文件的完整大小,但我希望有更好的方法。
But when I did tail file.txt > output.txt
output.txt ended up being like 1.8GB, much larger than the 10 lines I expected
这向我表明,该文件填充了 1.8GB 的二进制零,Cygwin 的 tail
命令在写入终端时忽略了它,但 Java 没有忽略它。这也可以解释你的 OutOfMemoryError
,因为 BufferedReader
继续读取数据寻找下一个 \r\n
,在内存溢出之前从未找到它。
我有一个非常大的文件 (~6GB),其中包含由 \r\n 分隔的固定宽度文本,因此我使用缓冲 reader 逐行读取。这个过程可以被中断或停止,如果是,它会使用检查点 "lastProcessedLineNbr" 快进到正确的位置以继续读取。这就是 reader 的初始化方式。
private void initializeBufferedReader(Integer lastProcessedLineNbr) throws IOException {
reader = new BufferedReader(new InputStreamReader(getInputStream(), "UTF-8"));
if(lastProcessedLineNbr==null){lastProcessedLineNbr=0;}
for(int i=0; i<lastProcessedLineNbr;i++){
reader.readLine();
}
currentLineNumber = lastProcessedLineNbr;
}
这似乎工作正常,我用这种方法读取和处理数据:
public Object readItem() throws Exception {
if((currentLine = reader.readLine())==null){
return null;
}
currentLineNumber++;
return parse(currentLine);
}
再一次,一切正常,直到我到达文档的最后一行。后一种方法中的 readLine() 抛出错误:
17:06:49,980 ERROR [org.jberet] (Batch Thread - 1) JBERET000007: Failed to run job ProdFileRead, parse, org.jberet.job.model.Chunk@3965dcc8: java.lang.OutOfMemoryError: Requested array size exceeds VM limit
at java.util.Arrays.copyOf(Arrays.java:3332)
at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:137)
at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:121)
at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:569)
at java.lang.StringBuffer.append(StringBuffer.java:369)
at java.io.BufferedReader.readLine(BufferedReader.java:370)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at com.rational.batch.reader.TextLineReader.readItem(TextLineReader.java:55)
奇怪的是,它似乎正在读取文件末尾并分配如此多 space 以致内存不足。我尝试使用 Cygwin 和 "tail file.txt" 查看文件的内容,在控制台中它给了我预期的 10 行。但是当我这样做时 "tail file.txt > output.txt" output.txt 最终变成了 1.8GB,比我预期的 10 行大得多。所以看起来 Cygwin 也在做同样的事情。据我所知,没有特殊的 EOF 字符。它只是数据的最后一个字节,并且突然结束。
任何人都知道我如何让它工作?我在想我可以求助于计算读取的字节数,直到我得到文件的完整大小,但我希望有更好的方法。
But when I did
tail file.txt > output.txt
output.txt ended up being like 1.8GB, much larger than the 10 lines I expected
这向我表明,该文件填充了 1.8GB 的二进制零,Cygwin 的 tail
命令在写入终端时忽略了它,但 Java 没有忽略它。这也可以解释你的 OutOfMemoryError
,因为 BufferedReader
继续读取数据寻找下一个 \r\n
,在内存溢出之前从未找到它。