0

我正在尝试读取一个到目前为止大约有 30 万行的文本文件。

我读得怎么样?

我正在使用 java.io.BufferedReader 阅读

这是一个代表我的方法的小代码片段。

int lineNumber = 1;
BufferedReader br = null;
String currentLine = null;
br = new BufferedReader(new FileReader(f));//here f will be the file name to be read, I have passed
while ((cuurentLine = br.readLine()) != null) {
  //here I have written logic to do processing after reading 1000 lines
  //line number = 1001 start processing, similarly it reads next 1000 lines, each line is put in a List collection
  //after reaching 1001 line clearing list and continuing the loop
}

我曾尝试使用 NIO2 以下情况

br = Files.newBufferedReader(Paths.get(inputFileName), StandardCharsets.UTF_16);

它导致了以下异常

exception :Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Unknown Source)
    at java.lang.AbstractStringBuilder.expandCapacity(Unknown Source)
    at java.lang.AbstractStringBuilder.ensureCapacityInternal(Unknown Source)
    at java.lang.AbstractStringBuilder.append(Unknown Source)
    at java.lang.StringBuffer.append(Unknown Source)
    at java.io.BufferedReader.readLine(Unknown Source)
    at java.io.BufferedReader.readLine(Unknown Source)
    at TexttoExcelMerger.readFileLineByLine(TexttoExcelMerger.java:66)
    at TexttoExcelMerger.main(TexttoExcelMerger.java:255)

首先,我的方法对吗?

NIO2、apache FileUtils 或任何其他 API 中是否有任何有效且快速的方法可以更快地读取文件,从而更快地改善我的文件读取过程。我可以读取前 1000 行之类的行集
br.readFirst(1000);
但不逐行读取或按照我的逻辑进行迭代吗?

4

2 回答 2

2

任何将整个文件读入内存的方法都注定要失败。文件迟早会超过可用内存,程序将停止运行,必须完全重新设计。这不是一个好的故障模式,因为在此期间用户无能为力。你在那个时候割草。您甚至可以尝试使用具有数十万行的文件来尝试它。一次重新思考和处理一条线。或者使用数据库。

注意不要自欺欺人。您正在使用 java.io 来读取文件。这里的 NIO2 组件很少。并不是说你根本需要它。

于 2013-05-20T12:41:05.530 回答
2

内存不足异常

您的内存不足是因为您试图将过多的文件读入内存。这可能以我能想到的两种方式发生。

你是故意的

如果你试图保存你读入的每一行,你就会耗尽内存。

while ((curentLine = br.readLine()) != null) {
    stringBuilder.append(currentLine);
}

如果您只是想一次保存 1000 行,那么您也许可以增加 Java 的堆大小-Xmx并且没问题。这完全取决于 1000 行占用多少内存。

你不小心这样做了

如果您正在阅读的文件没有任何换行符,那么br.readLine()将尝试阅读整个文件,并认为这是一个巨大的长行。

无需逐行阅读

如果您想象一个任意的文本文件,它只是一长串字符。其中一些字符 ( EOL) 对人类和许多程序具有特殊意义,但它们仍然只是字符。这意味着您不能只说“给我第 10 行文本”而不​​阅读它之前的每个字符(因为您永远不知道哪个字符可能是EOL您需要计算的)。

可以使用固定长度的记录格式:您说每一行将恰好是 $n$ 个单独的字符(例如 80 个)。现在如果要跳到第 10 行,可以跳到第 800 个字符。但是,如果您实际上使用的是 UTF-16,那么字符不是 a char,这实际上不起作用。

没关系,因为此时您可能应该使用数据库。

于 2013-05-20T13:03:31.140 回答