大文件读取

前阵子遇到一个关于大文件读取的问题:有一亿个整型,每行一个,如何找出其中最大的十个?

首先最基本的,从头开始读,插入排序,放入大小为10的优先队列,这样就可以取得最大的十个。但是,一条一条读,这样速度太慢了,有什么办法可以提高速度呢?
当时有种思路,把文件分区,分成n份,n个线程分别去读出对应块最大的十个,最后再合并。
另外一种想法,减少IO操作,就是BufferedReader,但是我自己实际操作后发现,在文件大小很小的时候,都是BufferedReader快些,但是读到大文件,如2G的文件,多线程的速度就非常快了。

第一行为BufferedReader所用的时间,其他为多线程信息。
分析一下文件读取流程:
首先内存空间分为内核空间和用户空间,在应用程序读取文件时,底层会发起系统调用,由系统调用将数据先读入到内核空间,然后再将数据拷贝到应用程序的用户空间供应用程序使用。而BufferedReader一次读取大块数据,IO操作是很耗时的,这样减少了IO的操作,省下了时间。
而相比内存映射,这个过程多了一个从内核空间到用户空间拷贝的过程。如果使用内存文件映射,文件会被映射到物理内存的某个地址上(不是数据加载到内存),此时应用程序读取文件的地址就是一个内存地址,而这个内存地址会被映射到了前面说到的物理内存的地址上。应用程序发起读之后,如果数据没有加载,系统调用就会负责把数据从文件加载到这块物理地址。应用程序便可以读取到文件的数据。省去了数据从内核空间到用户空间的拷贝过程。所以速度上也会有所提高。
那么在读取大文件的时候,利用java的内存映射,就可以在要读取某个地址时再将内容加载到内存。不需要一下子全部将内容加载进来。