java - 如何在 Java 中读取大文件(单个连续字符串)?
问题描述
我正在尝试读取一个非常大的文件(~2GB)。内容是带有句子的连续字符串(我想根据“。”来拆分它们)。无论我如何尝试,最终都会出现内存不足错误。
BufferedReader in = new BufferedReader(new FileReader("a.txt"));
String read = null;
int i = 0;
while((read = in.readLine())!=null) {
String[] splitted = read.split("\\.");
for (String part: splitted) {
i+=1;
users.add(new User(i,part));
repository.saveAll(users);
}
}
还,
inputStream = new FileInputStream(path);
sc = new Scanner(inputStream, "UTF-8");
while (sc.hasNextLine()) {
String line = sc.nextLine();
// System.out.println(line);
}
// note that Scanner suppresses exceptions
if (sc.ioException() != null) {
throw sc.ioException();
}
文件内容(由随机词组成,10 个词后有句号):
fmfbqi .xcdqnjqln kvjhw pexrbunnr cgvrqlr fpaczdegnb puqzjdbp gcfxne jawml aaiwwmo ugzoxn .opjc fmfbqi .xcdqnjqln kvjhw pexrbunnr cgvrqlr fpaczdegnb puqzjdbp gcfxne jawml aaiwwmo ugzoxn .opjc (so on)
请帮忙!
解决方案
因此,首先,根据对您问题的评论,正如 Joachim Sauer 所说:
如果没有换行符,则只有一行,因此只有一个行号。
所以你的用例充其量是有问题的。
让我们超越这一点,假设可能有换行符 - 或者更好的是,假设.
您要拆分的字符旨在成为换行符伪替换。
Scanner
尽管还有其他方法,但这并不是一个坏方法。由于您提供了 a Scanner
,让我们继续,但您要确保将它包裹在 a 周围BufferedReader
。您显然没有很多内存,并且 aBufferedReader
允许您读取由 缓冲的文件的“块” BufferedReader
,同时利用对Scanner
您来说完全模糊的功能,作为正在发生缓冲的调用者:
Scanner sc = new Scanner(new BufferedReader(new FileReader(new File("a.txt")), 10*1024));
这基本上是在做Scanner
你所期望的功能,但允许你一次缓冲 10MB,最大限度地减少你的内存占用。现在,你只要继续打电话
sc.useDelimiter("\\.");
for(int i = 0; sc.hasNext(); i++) {
String psudeoLine = sc.next();
//store line 'i' in your database for this psudeo-line
//DO NOT store psudeoLine anywhere else - you don't have memory for it
}
由于您没有足够的内存,因此迭代(和重新迭代)的明确事项是在读取文件后不要将文件的任何部分存储在 JVM 的堆空间中。阅读它,根据需要使用它,并允许将其标记为 JVM 垃圾回收。在您的情况下,您提到要将伪行存储在数据库中,因此您想读取伪行,将其存储在数据库中,然后丢弃它。
这里还有其他需要指出的事情,例如配置您的 JVM 参数,但我什至不愿提及它,因为仅将您的 JVM 内存设置为高也是一个坏主意——另一种蛮力方法。将 JVM 内存最大堆大小设置得更高没有任何问题,但是如果您仍在学习如何编写软件,那么学习内存管理会更好。当您进入专业发展阶段时,您以后遇到的麻烦就会减少。
另外,我提到Scanner
并且BufferedReader
因为您在问题中提到了这一点,但我认为检查deHaar 指出的java.nio.file.Path.lines()也是一个好主意。这基本上与我明确列出的代码做同样的事情,但需要注意的是,它仍然一次只能执行 1 行,而无法更改您“拆分”的内容。因此,如果您的文本文件中有 1 行,这仍然会给您带来问题,您仍然需要像扫描仪这样的东西来分割行。
推荐阅读
- r - 如何将一列时间数据四舍五入到 r 中最接近的 15 分钟?
- gpu - 如何使用 Profiling+openCL+Sycl+DPCPP 测量 GPU 的执行时间
- python - 将多个 ImageView 项添加到 Qt.Window 以在 python 的一个窗口中获取多个图像
- ruby-on-rails - Rails ActiveRecord 嵌套 .create!使用 PSQL POINT 类型
- excel - VBA单词将段落的第一句提取到Excel
- java - 打印 JTextField 在控制台上给出一个空白
- java - macOS 升级后 Grails 应用程序未运行
- sql - 在 AWS Athena 中添加月份日期列
- angular - 如何在没有任何动画的情况下打开角度材质弹出窗口(matDialog)
- java - 在检查指定位置是否设置位时,右移数字和左移位掩码哪个更好?