在 Java 中读取大文件

2022-08-31 15:00:50

我需要一个非常了解Java和内存问题的人的建议。我有一个大文件(大约1.5GB),我需要将这个文件剪切成许多(例如100个小文件)较小的文件。

我通常知道如何做到这一点(使用a),但我想知道你是否有任何关于记忆的建议,或者如何更快地做到这一点的提示。BufferedReader

我的文件包含文本,它不是二进制的,我每行大约有20个字符。


答案 1

为了节省内存,不要不必要地在内存中存储/复制数据(即不要将它们分配给循环外的变量)。只需在输入进入后立即处理输出即可。

无论你是否使用,这真的无关紧要。它不会像一些人隐含地暗示的那样花费更多的内存。它的最高值只会从性能中击中几个百分点。这同样适用于使用NIO。它只会提高可伸缩性,而不会提高内存使用率。只有当在同一文件上运行数百个线程时,它才会变得有趣。BufferedReader

只需循环浏览文件,在读入时立即将每行写入其他文件,计算行数,如果达到100,则切换到下一个文件,依此类推。

开球示例:

String encoding = "UTF-8";
int maxlines = 100;
BufferedReader reader = null;
BufferedWriter writer = null;

try {
    reader = new BufferedReader(new InputStreamReader(new FileInputStream("/bigfile.txt"), encoding));
    int count = 0;
    for (String line; (line = reader.readLine()) != null;) {
        if (count++ % maxlines == 0) {
            close(writer);
            writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("/smallfile" + (count / maxlines) + ".txt"), encoding));
        }
        writer.write(line);
        writer.newLine();
    }
} finally {
    close(writer);
    close(reader);
}

答案 2

首先,如果你的文件包含二进制数据,那么使用将是一个很大的错误(因为你会将数据转换为String,这是不必要的,很容易损坏数据);您应该使用 a 代替。如果它是文本数据,并且您需要沿换行符拆分它,则使用是可以的(假设文件包含合理长度的行)。BufferedReaderBufferedInputStreamBufferedReader

关于内存,如果您使用大小适中的缓冲区,应该不会有任何问题(我会使用至少1MB来确保HD主要进行顺序读取和写入)。

如果速度被证明是一个问题,你可以看看这些软件包 - 那些应该比快,java.niojava.io