java - 如何在Java中读取大文件(单个连续字符串)?

标签 java filestream bufferedinputstream

我正在尝试读取一个非常大的文件(~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 所说:

If there are no newlines, then there is only a single line and thus only one line number.

所以你的用例充其量是有问题的。

让我们超越这一点,假设可能有换行符 - 或者更好的是,假设您要分割的 . 字符旨在作为换行符替换。

Scanner 在这里并不是一个坏方法,尽管还有其他方法。由于您提供了 Scanner,让我们继续,但您要确保将其包装在 BufferedReader 周围。您显然没有太多内存,而 BufferedReader 允许您读取由 BufferedReader 缓冲的文件“ block ”,同时利用作为调用者,扫描器对您来说完全不知道缓冲正在发生:

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 垃圾回收。在您的情况下,您提到要将 psudeo 行存储在数据库中,因此您想读取 psudeo 行,将其存储在数据库中,然后将其丢弃。

这里还有其他事情需要指出,例如配置 JVM 参数,但我什至不愿意提及它,因为仅仅将 JVM 内存设置得较高也是一个坏主意 - 另一种强力方法。将 JVM 内存最大堆大小设置得更高并没有什么问题,但如果您仍在学习如何编写软件,那么学习内存管理会更好。当您进入职业发展阶段时,您遇到的麻烦就会减少。

另外,我提到了 ScannerBufferedReader 因为您在问题中提到了这一点,但我认为查看 java.nio.file.Path.lines()正如 deHaar 指出的那样也是一个好主意。这基本上与我明确列出的代码执行相同的操作,但需要注意的是它仍然一次只执行 1 行,而无法更改您要“拆分”的内容。因此,如果您的文本文件中有 1 个单行,这仍然会给您带来问题,并且您仍然需要扫描仪之类的工具来将行分段。

关于java - 如何在Java中读取大文件(单个连续字符串)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60416957/

相关文章:

java - iText 7 itextpdf.kernel.PdfException

java - 使用 StringTokenizer 递归解析字符串

java - 如何从匿名类中调用方法

c# - FileStream.SafeFileHandle *真的* 将当前流位置设置为 0 吗?

java - 我如何从缓冲读取器输入字符串?

java - map : How to get all keys associated with a value?

c# - 打开 C : Directly with `FileStream` without `CreateFile` API

c++ - 自定义 "ofstream"输出

java - 在java中缓冲缓冲流的结果是什么?

java - HttpUrlConnection 在 connect() 上获取响应主体