在java中以MB读取大文件的最佳方法

时间:2014-07-19 05:56:01

标签: java performance file-io memory-mapped-files

我正在浏览帖子,它说使用BufferedReader或MappedByteBuffer。我决定使用291.0 MB文件自行测试,但仍然无法决定

    BufferedReader reader = new BufferedReader(new FileReader("/Users/rachana/part-00000"));
    String line = null;
    while((line = reader.readLine())!=null) {
        System.out.println(line);
    }


    ~~~~~~ Heap utilization in MB ~~~~~~
    Start Date  21:10:20
    End Date 21:17:48
    Time used 448 second
           7.50 min
    Used Memory In MB:28
    Free Memory:81
    Total Memory:109
    Max Memory:1820

使用MappedByteBuffer

RandomAccessFile aFile = new RandomAccessFile
                ("/Users/rachana/part-00000", "r");
        FileChannel inChannel = aFile.getChannel();
        MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
        buffer.load(); 
        for (int i = 0; i < buffer.limit(); i++)
        {
            System.out.print((char) buffer.get());
        }
        buffer.clear(); // do something with the data and clear/compact it.
        inChannel.close();
        aFile.close();



~~~~~~ Heap utilization in MB ~~~~~~
 Start Date  21:20:40
 End Date 21:33:52
 Time used 792 sec / 13.2 min
Used Memory In MB:4 
Free Memory:104
Total Memory:109
Max Memory:1820

它明确指出MappedByteBuffer使用更少的内存但更多的时间,因为BufferedReader使用更多内存但时间更少。

我正在尝试使用MappedByteBuffer找到平衡读取线的方法。

任何建议都会有所帮助

4 个答案:

答案 0 :(得分:6)

您正在做的最慢的部分是打印到屏幕上。我建议你不要这样做,你会很好,MemoryMapped文件要快得多(如果你不是一次打印一个字符到控制台)

注意:除非您使用的是IS-8859-1或US-ASCII编码的文本文件,否则这两个不可互换。 BufferedReader用于文本,内存映射文件用于二进制文件。

BTW如果忽略您执行的GC数量,则无需查看使用的内存。如果您只关心在开始和结束时使用的内存,您应该在测量之前使用System.gc()进行完整的GC,并且我希望在两种情况下都会看到一个小的随机差异(可能是负数)。 / p>

如果你关于分配的情况,你需要更大的伊甸园大小,例如2 GB开始为空(在完整GC之后)或您可以使用分析器来测量分配。在第一种情况下,字符串将分配最多的数据,在第二种情况下,写入控制台将创建最多。

答案 1 :(得分:2)

  

它明确指出MappedByteBuffer使用的内存较少,但BufferedReader使用更多内存但时间更短的时间更长。

显然,这不可能是真的,事实并非如此。您使用MappedByteBuffer,而不是BufferedReader将整个300MB文件映射到内存中。解释是MappedByteBuffer内存不是来自堆。它使用内存,与文件大小一样多,BufferedReader代码更多。你只是在这里测量它。

同样地,你的时间测量也是无效的,因为它们由System.out.println()控制,它不是输入,并且希望它不是最终应用程序的一部分。

因此,您的基准测试在各方面都完全无效。

使用BufferedReader。你可以每秒读取数百万行。它足够快。

答案 2 :(得分:1)

我会选择第一个,除非你真的试图刮掉桶以进行内存优化。

原因:

  • 阅读代码更容易。
  • 用户更有可能注意到比24 MB额外内存加速100%。

答案 3 :(得分:1)

在进行文件I / O时,您应该记住,I / O操作可能比代码中CPU所做的任何工作都要慢得多。

但还有其他一些考虑因素。优化往往会使代码更复杂,更难理解。为了理解您的MappedByteBuffer代码,读者需要了解MappedByteBuffer除了需要了解文件输入所需的所有内容之外的其他工作方式。

通常会进行文件读取。因此,Java已经提供了帮助您的代码,这一点不应该让您感到惊讶。该代码将由专家编写,经过测试和调试。除非您有特殊要求,否则应始终使用此类代码而不是自己编写代码。也就是说,我建议使用BufferedReader(您的第一种方法)。