【发布时间】:2017-12-12 01:07:30
【问题描述】:
我有一个非常大的文本文件,其中每一行都必须被解析。 我想通过 x+100000 读取行 x 并将每一行添加到 List 中,使得 list.size
下面的代码是一个使用 BufferedReader 的版本。我很好地返回了前 100k 行,但在下一次调用中,从第 100k+1 行开始,它在第 150k 行左右开始减速,在第 165k 行附近它导致 OutOfMemoryError。我四处寻找一种方法来清空缓冲区,一旦它到达我想要开始添加到列表的行,但我找不到任何信息。我还试图找到一种方法来跳过 x 行,但我找不到任何东西。
public List<MyModel> retrieve(File inputFile, int startLine, String checksum) throws DaoException {
List<MyModel> result = new ArrayList<>();
try (BufferedReader br = new BufferedReader(new FileReader(inputFile))) {
String line = null;
int row = 0;
int iteration = 0;
try {
while (((line = br.readLine()) != null) && iteration < MAX_ROWS) {
row++;
LOGGER.info("row: " + row + ", iteration: " + iteration);
if (row > startLine && iteration < MAX_ROWS) {
MyModel model = this.fileReader.populateMyModel(line);
model.setFileChecksum(checksum);
result.add(model);
iteration++;
}
if (iteration >= MAX_ROWS) {
break;
}
}
} catch (Exception e) {
throw new FileReaderException("Failed to read line " + iteration + " of " + inputFile.getAbsolutePath(), e);
}
} catch (FileNotFoundException e1) {
throw new FileReaderException("Could not find file '" + inputFile.getAbsolutePath() + "'.", e1);
} catch (IOException e1) {
throw new FileReaderException("Could not read file '" + inputFile.getAbsolutePath() + "'.", e1);
}
return result;
}
在尝试了解如何跳过行时,我遇到了 Java 8 Stream 读取文件的方式,下面的代码是我尝试以这种方式处理它。这在第一次调用时也很有效,返回前 100k 行。对于从第 100k+1 行开始的第二次调用,它返回“java.lang.IllegalStateException:流已被操作或关闭”。此外,我只想读取 x 到 x+100k 行然后返回,而不是循环浏览文件的所有行。我是这个 Stream 对象的新手,但似乎使用它应该提供解决方案。
public List<MyModel> retrieve(File inputFile, int startLine, String checksum) throws DaoException {
List<MyModel> result = new ArrayList<>();
try (Stream<String> lines = Files.lines(inputFile.toPath(), Charset.defaultCharset())) {
lines.skip(startLine);
lines
.filter(line -> result.size() <= 100000)
.forEach(line -> {
result.add(this.fileReader.populateMyModel(line));
if (result.size() % 10000 == 0) {
LOGGER.info("result size: " + result.size());
}
});
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}
任何建议都会有所帮助。
【问题讨论】:
-
你应该用
skip().filter(...)...链接,跳过返回一个新的流,你不能重用一个消费的流。 -
@holi-java - 虽然我的问题文本中提到了该异常,但该链接并未解决如何从文件中读取一组特定的行号,这就是这个问题的意义所在.
-
好吧,如果你认为它是合理的。我恢复它。确实,在将您的答案标记为重复之前,我是答案的第一个投票者。我只想告诉你那里有完整的详细答案。
标签: java java-8 stream java-stream