用于创建大型 CSV 文件的 java IO 最佳实践
Posted
技术标签:
【中文标题】用于创建大型 CSV 文件的 java IO 最佳实践【英文标题】:Best Practices for java IO for creating a large CSV file 【发布时间】:2011-11-26 07:03:02 【问题描述】:您好,我需要创建几个大型 CSV 文件,这些文件的顺序可能是 200 万。所以我想知道如何有效地做到这一点..因此我脑海中浮现的问题很少
1 .当我们通过 BufferedWriter 写入文件时,我们应该多久刷新一次?但是我认为 bufferedWriter 维护自己的缓冲区,一旦缓冲区已满,它就会自动刷新它,如果是这种情况,那么为什么还有 flush 方法呢??
因为我要创建的文件会很大。所以当我开始写入文件时,文件会自动提交到磁盘吗? (在调用 writer.close() 之前)或整个文件保留在主内存中,直到我关闭 writer?
提交是指已写入部分的任何部分都不在主内存中,即它已准备好进行 GC【问题讨论】:
数据从何而来?另一个基于磁盘的存储,通过网络还是来自内存? 数据来自数据库,需要生成少量业务验证和处理这些文件 【参考方案1】:BufferedWriter
实现应该在适当的时候很好地完成刷新。在你的情况下,你永远不需要打电话给flush
。
至于为什么会有flush
方法,这是因为有时您希望立即写入输出,而不是等待BufferedWriter
的缓冲区变满。 BufferedWriter
不只是用于文件;它也可以用于写入控制台或套接字。例如,您可能希望通过网络发送一些数据,但数据量不足以导致BufferedWriter
自动刷新。为了立即发送此数据,您可以使用flush
。
您写入BufferedWriter
的所有数据不会同时保留在内存中。当BufferedWriter
的缓冲区填满时,它会被分段写出(刷新)。在最后调用 close
后,BufferedWriter
将对其缓冲区中尚未写入磁盘的所有剩余内容进行最后一次刷新并关闭文件。
【讨论】:
【参考方案2】:如果将写入器包装在 BufferedWriter 中,则在物理写入磁盘之前指定要保存在内存中的字节数。 (如果您不指定,则有默认值。我认为是 8k,但请不要引用它作为福音。)
如果你使用 PrintWriter,我认为它每行都会写入磁盘。
其他写入器在每次 i/o 调用时写入磁盘。没有缓冲。这通常会导致糟糕的表现。这就是为什么所有磁盘写入器都应该包装在 BufferedWriter 中的原因。
【讨论】:
【参考方案3】:我倾向于分段工作,每 1k 或 2k 行后刷新到磁盘。有了这么多数据,它似乎正在推动内存限制。由于这个操作可能已经很慢了,为了安全起见,失败并经常写入磁盘。
反正那是我的 0.02 美元 :)
【讨论】:
【参考方案4】:BufferedWriter
使用固定大小的缓冲区,当缓冲区满时会自动刷新。因此任何大文件都会被分块写入。
flush 方法之所以存在,是因为有时您可能希望在缓冲区满之前将某些内容写入磁盘。一个典型的例子是包装了 SocketOutputStream 的 BufferedWriter。如果你这样做:
writer.write(request);
reader.read(response);
您的线程可能会无限期地阻塞,因为在缓冲区满之前不会发送请求。因此,您会这样做:
writer.write(request);
writer.flush(); // make sure the request is sent now
reader.read(response);
改为。
【讨论】:
以上是关于用于创建大型 CSV 文件的 java IO 最佳实践的主要内容,如果未能解决你的问题,请参考以下文章
使用 PHP/MySQL 导出大型 CSV 数据的最佳方法是啥?