jjzjj

java - PrintWriter vs PrintStream vs OutputStreamWriter 时间成本

coder 2024-04-02 原文

如您所知,我们在 Java 中有多种工具可用于将数据写入流。
在此示例代码中,我按运行时间对它们进行了比较。
有人可以准确解释吗?谢谢。
这是代码:

import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.PrintWriter;

public class IOtests
{

public static void main(String[] args) throws Exception
{
    char[] chars = new char[100];
    byte[] bytes = new byte[100];
    for (int i = 0; i < 100; i++)
    {
        chars[i] = (char) i;
        bytes[i] = (byte) i;
    }
    OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(
            "output.txt"));
    long a = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++)
        for (char j : chars)
            out.write(j);
    System.out.println("OutputStreamWriter writing characters: "
            + (System.currentTimeMillis() - a));
    out = new OutputStreamWriter(new FileOutputStream("output.txt"));
    a = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++)
        for (byte j : bytes)
            out.write(j);
    System.out.println("OutputStreamWriter writing bytes: "
            + (System.currentTimeMillis() - a));
    PrintStream out1 = new PrintStream("output.txt");
    a = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++)
        for (char j : chars)
            out1.write(j);
    System.out.println("PrintStream writing characters: "
            + (System.currentTimeMillis() - a));
    out1 = new PrintStream("output.txt");
    a = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++)
        for (byte j : bytes)
            out1.write(j);
    System.out.println("PrintStream writing bytes: "
            + (System.currentTimeMillis() - a));
    PrintWriter out2 = new PrintWriter("output.txt");
    a = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++)
        for (char j : chars)
            out2.write(j);
    System.out.println("PrintWriter writing characters: "
            + (System.currentTimeMillis() - a));
    out1 = new PrintStream("output.txt");
    a = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++)
        for (byte j : bytes)
            out2.write(j);
    System.out.println("PrintWriter writing bytes: "
            + (System.currentTimeMillis() - a));
}

}

结果:

OutputStreamWriter writing characters: 4141
OutputStreamWriter writing bytes: 3546
PrintStream writing characters: 86516
PrintStream writing bytes: 70484
PrintWriter writing characters: 938
PrintWriter writing bytes: 2484

请注意,所有时间均以毫秒为单位。

最佳答案

我已将您的问题简化为本质:

public class Test {
  static byte[] bytes = new byte[10_000_000];
  static {
    for (int i = 0; i < bytes.length; i++) bytes[i] = (byte) (i%100+32);
  }
  public static void main(String[] args) throws Exception {
    writer(true);
    writer(false);
    stream(true);
    stream(false);
  }

  static void writer(boolean flush) throws IOException {
    Writer out = new FileWriter("output.txt");
    long a = System.currentTimeMillis();
    for (byte j : bytes) {
      out.write(j);
      if (flush) out.flush();
    }
    out.close();
    System.out.println("FileWriter with" + (flush? "":"out") + " flushing: " +
        (System.currentTimeMillis() - a));
  }
  static void stream(boolean flush) throws IOException {
    OutputStream out = new FileOutputStream("output.txt");
    long a = System.currentTimeMillis();
    for (byte j : bytes) {
      out.write(j);
      if (flush) out.flush();
    }
    out.close();
    System.out.println("FileOutputStream with" + (flush? "":"out") + " flushing: " +
        (System.currentTimeMillis() - a));
  }
}

注意事项:

  • 完成后正确关闭资源;
  • 用单循环代替双循环,但数组更大;
  • 避免编写控制字符以规避自动刷新行为;
  • 仅使用字节数组,因为在所有情况下您只测试一种方法:write(int)。因此,无论您使用字节还是字符都没有区别;
  • 删除了除 FileWriterFileOutputStream 之外的所有内容,因为所有其他情况都归结为这两个;
  • 在两种模式下测试编写器和输出流:每次写入后刷新,直到关闭才刷新。

现在,当你运行它时,你会得到如下输出:

FileWriter with flushing: 28235
FileWriter without flushing: 828
FileOutputStream with flushing: 23984
FileOutputStream without flushing: 23641

那么,有什么教训呢?

  • 所有编写器都被缓冲,因为它们在内部委托(delegate)给本身被缓冲的 StreamEncoder
  • FileOutputStream 没有缓冲;
  • 逐字节非缓冲写入非常慢。

好的做法要求您始终进行缓冲写入:要么使用缓冲接收器,要么在您这边维护一个显式缓冲区。

关于java - PrintWriter vs PrintStream vs OutputStreamWriter 时间成本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18431188/

有关java - PrintWriter vs PrintStream vs OutputStreamWriter 时间成本的更多相关文章

随机推荐