PrintWriter vs PrintStream vs OutputStreamWriter timecosts

如您所知,我们在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写字符:4141
OutputStreamWriter写入字节:3546
PrintStream写字符:86516
PrintStream写入字节:70484
PrintWriter写字符:938
PrintWriter写入字节: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)); } } 

笔记:

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

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

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

那么,教训是什么?

  • 所有StreamEncoder都是缓冲的,因为它们在内部委托给StreamEncoderStreamEncoder本身是缓冲的;
  • FileOutputStream未缓冲;
  • 非缓冲的逐字节写入非常慢。

良好实践要求您始终执行缓冲写入:使用缓冲接收器,或者在您身边维护显式缓冲区。