2013-08-25 18 views
6

わかっていますが、われわれはストリームにデータを書き込むためのいくつかのツールをjavaに用意しています。
このサンプルコードでは、ランタイムでそれらを比較しました。
誰かが正確に説明できますか?ありがとう。PrintWriterとPrintStreamとOutputStreamWriterのタイムコード

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

すべての時刻はミリ秒単位であることに注意してください。

+1

出力を決して閉じることはできないので、すべてをバッファリングすることができます。さらに、ガーベジコレクションなどを実行していないJITウォームアップを提供していません。「PrintWriter writes bytes」は、*文字*のみを書き込むと誤解されます。暗黙的なバイトからintへの変換があります。さらに、一度に1バイトまたは1文字を書くことは、ほとんどの賢明なコードでは非現実的です。あなたは 'byte []'、 'char []'または 'String'を使ってオーバーロードを使います。 –

+1

あなたのタイミング番号は非常に疑わしいです。 Javaで正しいベンチマークを書く方法については、[this thread](http://stackoverflow.com/questions/504103/how-do-i-write-a-correct-micro-benchmark-in-java)を参照してください。 –

+1

@TedHoppこのアドバイスをすべて取っておけば、ディスク上のファイルに書き込むこと自体が予測不可能なプロセスです。 * nix上では、比較的予測可能なシンクとして '/ dev/null'を使うことができます。 Windowsでは、神は何を知っています。 –

答えて

3

私はその本質にあなたの質問を削減しました:

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)); 
    } 
} 

注:

  • 行われたときに適切なリソースをクローズします。
  • ダブルループはシングルループに置き換えられますが、より大きな配列になります。
  • 自動フラッシュ動作を回避するための制御文字の書き込みを避ける。
  • すべての場合に1つのメソッドしかテストしていないので、バイト配列を使用してください:write(int)。したがって、バイトまたは文字を使用しているかどうかには違いはありません。
  • FileWriterFileOutputStream以外のすべてが削除されています。
  • ライターと出力ストリームの両方を2つのモードでテストします。各書き込み後にフラッシュし、クローズするまでフラッシュしません。今

、あなたがこれを実行すると、次のような出力が得られます。

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

ので、レッスンは何ですか?

  • 内部的には、それ自体がバッファされているStreamEncoderに委任されているため、すべての書き込みがバッファリングされます。
  • FileOutputStreamはバッファされません。
  • バイト単位での書き込みが非常に遅い。バッファリングシンクを使用して、またはあなたの側で明示的にバッファを維持し、次のいずれか

グッドプラクティスは、あなた常にがバッファ書き込みを行うことを要求します。

+0

実際にPrintWriterとPrintStreamとOutputStreamWriterの違いを理解することはできません。ファイルを使用するのは単なる例でした。操作速度とファイルをストリームのシンクとして比較するために非常に多くの計算機/バイトを書くだけでしたとても妥当でした。バッファを使わずにファイルに書き込むのが遅いというこの事実を考慮せずに、私が端末に書き込んでいると仮定します。どのツールを使用する必要がありますか? –

+0

シンクとは関係ありません。バッファされていないI/Oは、1バイトあたり1つのシステムコールを必要とするため、遅いです。したがって、これらの問題は、「仮想」ストリームに書き込むときにのみ適用されます。これは、JVM自体の外部には何もしません。たとえば、 'StringWriter'または' ByteArrayOutputStream'です。 –

+0

'PrintWriter'と' PrintStream'は、後者がレガシークラスです。文字データを書くときは常に 'Writer'を、バイナリデータを書くときは' OutputStream'を優先するべきです。 –

関連する問題