题
我有一个大小2GB的文件,其中包含学生记录。我需要根据每个记录中的某些属性找到学生,并创建一个带有结果的新文件。被过滤的学生的顺序应与原始文件相同。使用Java IO API和线程没有内存问题的有效和最快的方法是什么? JVM的Maxheap尺寸设置为512MB。
解决方案
- 文件的2GB巨大,您应该选择DB。
- 如果您真的想使用 Java I/O API, ,然后尝试一下: 使用Java有效地处理大型数据文件 和这个: 调整Java I/O性能
其他提示
什么样的文件?基于文本,例如CSV?
最简单的方法是执行像GREP一样的事情:按行读取文件,分析线,检查您的过滤器标准,如果匹配,输出结果行,然后转到下一行,直到完成文件。这是非常有效的,因为您仅将当前线(或更大的缓冲区)同时加载。您的过程只需阅读一次整个文件。
我认为多个线程不会有太大帮助。这将使事情变得更加复杂,并且由于该过程似乎是i/o绑定的,因此尝试读取具有多个线程的同一文件可能不会改善吞吐量。
如果您发现自己需要经常执行此操作,并且每次都要慢慢进行文件,则需要构建某种索引。最简单的方法是首先将文件导入DB(可以是嵌入式DB或HSQL)。
除非您发现这种简单的方法对您需要的东西不起作用,否则我不会过度复杂化。本质上,您只需要:
- 打开输入流到2GB文件,记住到缓冲区(例如,用BufferedInputStream包装)
- 打开输出流到您要创建的过滤文件
- 从输入流中读取第一个记录,查看任何属性以确定您是否需要“需要”;如果这样做,请将其写入输出文件
- 重复其余记录
在我的一个带有极度适度硬件的测试系统上,盒子外面的FileInputStream在25秒内读取约500 MB,即可能不到2分钟来处理您的2GB文件,并且默认的缓冲区大小基本上一样好, (请参阅 BufferedInputStream定时 我为更多详细信息制作了)。我想,使用最先进的硬件,很有可能时间会减半。
无论您是需要付出很多努力来减少2/3分钟还是在等待运行的时候就去找Wee,这是一个决定,您必须根据自己的要求做出。我认为,除非您需要在同一数据集上进行许多不同的处理运行,否则数据库选项不会为您购买太多(并且还有其他解决方案不会自动含义数据库)。
我想你应该使用 内存映射 文件。这将帮助您将较大的文件映射到较小的内存中。此操作将像虚拟内存一样,就性能而言,映射的文件比流写入/读取的速度更快。