Java IO:逐行写入文本文件

时间:2014-07-31 08:52:54

标签: java file file-io java-io

我有一个要求,我需要逐行编写文本文件。 行数可达80K。我打开文件输出流并在for循环中,迭代列表并形成一行并将该行写入文件。

这意味着对文件进行了80K写操作。

频繁打开和写入文件会影响性能。 任何人都可以建议在Java IO中满足此要求的最佳方式吗?

感谢。

3 个答案:

答案 0 :(得分:3)

您尚未发布任何代码,但只要您的写入被缓冲,您几乎不会注意到性能。使用BufferedWriter.write()后跟BufferedWriter.newLine(),,尽可能避免冲洗。不要'形成一条线',只要你有它就写下你必须写的东西。如果不是你所观察到的所有开销实际上可能是字符串连接而不是I / O.

其他答案中提到的替代方案或者相当于以更多巴洛克方式实施,或者涉及NIO,这不会更快。

答案 1 :(得分:2)

使用BufferedOutputStream。有了它,所有写入首先写入缓冲区而不是直接写入磁盘。仅当缓冲区已满并且关闭或刷新流时,才会写入磁盘。默认缓冲区大小为8192字节,但您可以指定自己的缓冲区大小。

以下是使用默认缓冲区大小的示例:

PrintWriter out = null;
try {
  out = new PrintWriter(new OutputStreamWriter(
      new BufferedOutputStream(new FileOutputStream("out.txt")), "UTF-8"));
  for(int i = 0; i < 80000; i++) {
    out.println(String.format("Line %d", i));
  }      
} catch (UnsupportedEncodingException e) {
  e.printStackTrace();
} catch (FileNotFoundException e) {
  e.printStackTrace();
} finally {
  if(out != null) {
    out.flush();
    out.close();
  }
}

答案 2 :(得分:0)

以下是我在设计快速文件IO时使用的启发式方法,以及一组用于测试不同备选方案的基准测试。

启发式:

  1. 预先分配文件,要求操作系统调整文件大小是昂贵的,
  2. 尽可能地流式传输数据,避免在旋转光盘上执行搜索,
  3. 批量写入(同时注意不要造成过多的GC问题),
  4. 在为ssd设计时,避免更新数据......这是ssd上最慢的操作。有关SSD怪癖的完整指南可以阅读here
  5. 尽可能避免在缓冲区之间复制数据(这是java nio可以提供帮助的地方)和
  6. 如果可能,请使用内存映射文件。内存映射文件在Java中使用,但是将磁盘写入操作系统 异步执行通常要快一个数量级 而不是替代品;即BufferedWriter和RandomAccessFile。
  7. 我前一段时间写过以下文件基准测试。给他们一个跑步:https://gist.github.com/kirkch/3402882

    当我运行benchmarks时,对着标准的旋转磁盘,我得到了这些结果:

    Stream Write: 438
    Mapped Write: 28
    Stream Read: 421
    Mapped Read: 12
    Stream Read/Write: 1866
    Mapped Read/Write: 19
    

    所有数字均以毫秒为单位,因此越小越好。请注意,内存映射文件始终执行其他所有方法。

    在编写这些类型的系统时,我发现的另一个惊喜是,在Java的更高版本中,使用BufferedWriter可能比直接使用FileWriter或RandomAccessFile慢。事实证明,缓冲现在已经降低了,我认为它发生在Sun重写java.io以使用通道和字节缓冲区时。然而,添加自己的缓冲的建议仍然是常见的做法。当您首先测量目标环境时,请随意调整上面的基准代码以进行进一步的实验。

    在寻找支持上述一些事实的链接时,我遇到了Martin Thompson's post on this topic。非常值得一读。