gpt4 book ai didi

java - 如何在有限内存中处理大量小文件?

转载 作者:行者123 更新时间:2023-11-30 10:47:12 25 4
gpt4 key购买 nike

问题描述如下:

我在一个目录中有大量的小日志文件,假设:

  1. 所有文件都遵循命名约定:yyyy-mm-dd.log,例如:2013-01-01.log、2013-01-02.log。
  2. 大约有 1,000,000 个小文件。
  3. 所有文件的总大小为数 TB。

现在我必须为每个文件中的每一行添加一个行号,行号是累积的,分布在文件夹中的所有文件(文件按时间戳排序)中。例如:

  • 2013-01-01.log中,行号1~2500
  • 2013-01-02.log中,行号2501~7802
  • ...
  • 2016-03-26.log中,行号从1590321~3280165

所有文件都被覆盖以包含行号。

约束是:

  1. 存储设备是SSD,可以同时处理多个IO请求。
  2. CPU 足够强大。
  3. 您可以使用的总内存为 100MB。
  4. 尝试最大限度地提高应用程序的性能。
  5. 用 Java 实现和测试。

经过思考和搜索,这里是最好的solution我想过。 The code有点很长,所以我只对每个步骤做一个简单的描述:

  1. 并发计算每个文件的行数,并将映射保存到一个ConcurrentSkipListMap中,key是文件名,value是文件的行数,键是有序的。

  2. 通过遍历ConcurrentSkipListMap统计每个文件的起始行数,例如2013-01-01.log的起始行数和行数分别为1和1500,那么2013-01-02.log的起始行号就是1501。

  3. 为每个文件的每一行添加行号:使用BufferedReader逐行读取每个文件,添加行号然后使用BufferedWriter<写入相应的tmp文件。创建线程池并并发处理。

  4. 同时使用线程池将所有 tmp 文件重命名回原来的名称。

我已经在我的 MBP 上测试了程序,第 1 步和第 3 步是预期的瓶颈。你有更好的解决方案,或者对我的解决方案进行一些优化吗?提前致谢!

最佳答案

不确定这个问题是否符合 Q&A 的 SO 模型,但我尝试了一些提示来寻找答案。

事实 1) 给定 1M 文件和 100MB 限制,几乎没有办法将所有文件的信息同时保存在内存中。除了可能像过去我们用 C 编程时那样做很多小摆弄。

事实 2) 我看不出有什么方法可以绕过一次读取所有文件以计算行号然后重写它们,这意味着再次读取它们。

A) 这是作业题吗?在 Java 7 或 8 中,可能有一种方法可以从文件夹中一个一个地懒惰地生成文件名,但我不知道。如果有,请使用它。如果没有,您可能需要生成文件名而不是列出它们。这将要求您可以插入开始日期和结束日期作为输入。不确定这是否可能。

B) 假设有一个懒惰的 Iterator<File> ,无论是从jdk来列出文件还是自己实现来生成文件名,都得到N个,把工作分给N个线程。

C) 现在每个线程都处理它的文件切片,读取它们并仅保留其切片的总行数。

D) 从每个切片的总数计算每个切片的起始编号。

E) 再次在 N 个线程上分发迭代器以进行行编号。写入后立即重命名 tmp 文件,不要等待一切完成,这样就不必再次遍历所有文件。

在每个时间点,保存在内存中的信息相当小:每个线程一个文件名,整个切片的行数,正在读取的文件的当前行。如果 N 不是特别大,100MB 就足够了。

编辑:Some sayFiles.find()是懒惰填充的,但我无法轻易找到它背后的代码(Java 8 中的一些 DirectoryStream)来查看懒惰是否仅适用于一次读取一个文件夹的全部内容,或者是否确实读取了一个文件名一次。或者这是否取决于所使用的文件系统。

关于java - 如何在有限内存中处理大量小文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36236747/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com