1

我有一个 2GB 大小的文件,里面有学生记录。我需要根据每条记录中的某些属性找到学生,并创建一个包含结果的新文件。过滤学生的顺序应与原始文件中的顺序相同。在没有内存问题的情况下,使用 Java IO API 和线程执行此操作的最有效和最快的方法是什么?JVM 的最大堆大小设置为 512MB。

4

4 回答 4

6

什么样的文件?基于文本,如 CSV?

最简单的方法是执行类似 grep 的操作:逐行读取文件,解析该行,检查您的过滤条件,如果匹配,则输出结果行,然后转到下一行,直到文件完成。这是非常节省内存的,因为您只能同时加载当前行(或稍大一点的缓冲区)。您的进程只需要通读整个文件一次。

我认为多个线程不会有太大帮助。这会使事情变得更加复杂,并且由于进程似乎无论如何都是 I/O 绑定的,因此尝试使用多个线程读取同一个文件可能不会提高吞吐量。

如果你发现你需要经常这样做,并且每次浏览文件太慢,你需要建立某种索引。最简单的方法是首先将文件导入数据库(可以是嵌入式数据库,如 SQLite 或 HSQL)。

于 2010-08-20T01:27:55.420 回答
5

在您发现无聊的简单方法无法满足您的需求之前,我不会使这变得过于复杂。基本上你只需要:

  • 打开输入流到 2GB 文件,记住缓冲(例如通过 BufferedInputStream 包装)
  • 打开输出流到您要创建的过滤文件
  • 从输入流中读取第一条记录,查看任何属性以决定是否“需要”它;如果这样做,请将其写入输出文件
  • 重复剩余记录

在我的一个硬件极其适中的测试系统上,开箱即用的 FileInputStream 周围的 BufferedInputStream 在 25 秒内读取了大约 500 MB,即处理 2GB 文件可能不到 2 分钟,并且默认缓冲区大小基本上和它一样好(有关更多详细信息,请参阅我制作的BufferedInputStream 计时)。我想用最先进的硬件很可能时间会减半。

无论您是需要付出很多努力来减少 2/3 分钟,还是只是在等待它运行时稍作休息,这都是您必须根据自己的要求做出的决定。我认为数据库选项不会给您带来太多收益,除非您需要对同一组数据进行大量不同的处理(并且还有其他解决方案并不意味着数据库)。

于 2010-08-20T02:47:44.157 回答
2
  1. 2GB 的文件是巨大的,你应该去一个 db。
  2. 如果你真的想使用Java I/O API,那么试试这个:Handling large data files Effective with Java和这个:Tuning Java I/O Performance
于 2010-08-20T01:19:57.280 回答
0

我认为您应该使用内存映射文件。这将帮助您将较大的文件映射到较小的内存。这将像虚拟内存一样,就性能而言,映射文件比流写入/读取更快。

于 2010-08-20T05:04:33.897 回答