【问题标题】:Java IO : Writing into a text file line by line [closed]Java IO:逐行写入文本文件[关闭]
【发布时间】:2014-09-23 03:31:32
【问题描述】:

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

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

频繁打开和写入文件会影响性能。 任何人都可以提出一种在 Java IO 中解决此要求的最佳方法吗?

谢谢。

【问题讨论】:

标签: java file file-io java-io


【解决方案1】:

您尚未发布任何代码,但只要您的写入被缓冲,您几乎不会注意到性能。使用BufferedWriter.write() 后跟BufferedWriter.newLine(), 并尽可能避免冲洗。不要“排成一行”,只要写下你必须写的东西。您观察到的大部分开销实际上可能是字符串连接而不是 I/O。

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

【讨论】:

    【解决方案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();
      }
    }
    

    【讨论】:

      【解决方案3】:

      以下是我在设计快速文件 IO 时用来帮助我做出决策的启发式方法以及我用来测试不同替代方案的一组基准。

      启发式:

      1. 预分配文件,要求操作系统调整文件大小是昂贵的,
      2. 尽可能流式传输数据,避免搜索,因为它们不会在旋转磁盘上执行,
      3. 批量写入(同时注意不要造成过多的 GC 问题),
      4. 在为 ssd 设计时,避免就地更新数据。这是 ssd 上最慢的操作。可以阅读有关 SSD 怪癖的完整指南here
      5. 尽可能避免在缓冲区之间复制数据(这是 java nio 可以提供帮助的地方)和
      6. 尽可能使用内存映射文件。内存映射文件在 Java 中使用不足,但是将磁盘写入移交给操作系统 异步执行通常要快一个数量级 比替代品;即 BufferedWriter 和 RandomAccessFile。

      我不久前编写了以下文件基准测试。试一试: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 以使用通道和字节缓冲区时。然而,添加自己的缓冲的建议仍然是常见的做法。由于 aways 首先在您的目标环境中进行测量,因此请随时调整上面的基准代码以进行进一步试验。

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

      【讨论】:

        猜你喜欢
        • 2015-03-11
        • 2021-12-30
        • 2023-03-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多