1) バッファリングされたストリームはバックグラウンドでどのように機能しますか? 通常のストリームとどのように異なりますか? また、それらを使用する利点は何ですか?
2)DataInputStream
もバイトベースです。しかし、それにはメソッドがありreadLine()
ます。ここでのポイントは何ですか?
1) バッファリングされたストリームはバックグラウンドでどのように機能しますか? 通常のストリームとどのように異なりますか? また、それらを使用する利点は何ですか?
2)DataInputStream
もバイトベースです。しかし、それにはメソッドがありreadLine()
ます。ここでのポイントは何ですか?
バッファリングされた Readers/Writers/InputStreams/OutputStreams は、最適化のために大きなチャンクで OS を読み書きします。ライターと出力ストリームの場合、大きなチャンクを書き出すのに十分な量が収集されるまで、データはメモリにバッファリングされます。リーダーと入力ストリームの場合、大きなチャンクがディスク/ネットワーク/... からバッファーに読み取られ、バッファーが空になるまですべての読み取りがそのバッファーから行われ、新しいチャンクが読み込まれます。
DataInputStream は確かにバイトベースです。readLine メソッドは非推奨です。内部的には、ディスク/ネットワーク/... からバイトを読み取り、完全な行を収集するまでバイトごとに読み取ります。したがって、このストリームは、ソースとして BufferedInputStream を使用することで高速化できます。これにより、行のバイトがディスクから直接ではなくメモリ内バッファーから読み取られるようになります。
BufferedInputStream javadoc から:
BufferedInputStream は、別の入力ストリームに機能を追加します。つまり、入力をバッファリングし、mark メソッドと reset メソッドをサポートする機能です。BufferedInputStream が作成されると、内部バッファー配列が作成されます。ストリームからのバイトが読み取られるかスキップされると、内部バッファーは、一度に多くのバイトが含まれている入力ストリームから必要に応じて補充されます。マーク操作は入力ストリーム内のポイントを記憶し、リセット操作は、含まれている入力ストリームから新しいバイトが取得される前に、最新のマーク操作以降に読み取られたすべてのバイトを再読み取りします。
内部的にはバッファ配列が使用され、基礎となる入力ストリームから個別にバイトを読み取る代わりに、バッファを満たすのに十分なバイトが読み取られます。これにより、基本的な入力ストリームで必要な読み取りが少なくなるため、通常はパフォーマンスが向上します。
BufferedOutputStream の場合は逆になります。
mark() と reset() は次のように使用できます。
1 BufferedInputStream bis = new BufferedInputStream(is);
2 byte[] b = new byte[4];
3 bis.read(b); // read 4 bytes into b
4 bis.mark(10); // mark the stream at the current position - we can read 10 bytes before the mark point becomes invalid
5 bis.read(b); // read another 4 bytes into b
6 bis.reset(); // resets the position in the stream back to when mark was called
7 bis.read(b); // re-read the same 4 bytes as line 5 into b
マーク/リセットをもう少し説明するには...
BufferInputStream は、バッファ内の現在の位置を内部的に記憶しています。バイトを読み取ると、位置が増加します。mark(10) を呼び出すと、現在の位置が保存されます。後続の read の呼び出しは現在の位置をインクリメントし続けますが、reset の呼び出しは現在の位置を mark が呼び出されたときの値に戻します。
mark への引数は、mark を呼び出した後、マーク位置が無効になる前に読み取ることができるバイト数を指定します。マーク位置が無効になると、reset を呼び出してそこに戻ることはできなくなります。
たとえば、上記の 4 行目で mark(2) が使用されていた場合、6 行目で reset() が呼び出されたときに IOException がスローされます。これは、2 バイト以上を読み取ったためにマーク位置が無効になったためです。
バッファリングされていない I/O では、各読み取りまたは書き込み要求がオペレーティング システムに直接渡されます。Java のバッファリングされた I/O ストリームは、独自のメモリ バッファ (通常はバイト配列) に対してデータを読み書きします。オペレーティング システムへの呼び出しは、バッファーが空 (読み取りの実行時) またはバッファーがいっぱい (書き込みの実行時) の場合にのみ行われます。アプリケーションの重要なポイントの後でバッファを手動でフラッシュすることをお勧めします。
オペレーティング システムの API 呼び出しによってディスク アクセスやネットワーク アクティビティなどが発生する可能性があるため、これにはかなりのコストがかかる可能性があります。バッファを使用してオペレーティング システムのネイティブ I/O をより大きなチャンクにバッチ処理すると、多くの場合、パフォーマンスが大幅に向上します。
バッファリングされたストリームは、 – nomen est omen – bufferingによって、より大きなチャンクでデータを読み書きします。基になるストリームによっては、これによりパフォーマンスが大幅に向上する可能性があります。
java.io.BufferedOutputStreamの Javadocから:
このような出力ストリームを設定することにより、アプリケーションは、バイトが書き込まれるたびに基礎となるシステムへの呼び出しを必ずしも発生させることなく、基礎となる出力ストリームにバイトを書き込むことができます。
この種のオーバーヘッドを削減するために、Java プラットフォームはバッファリングされた I/O ストリームを実装しています。バッファリングされた入力ストリームは、バッファと呼ばれるメモリ領域からデータを読み取ります。ネイティブ入力 API は、バッファーが空の場合にのみ呼び出されます。同様に、バッファリングされた出力ストリームはデータをバッファに書き込み、ネイティブ出力 API はバッファがいっぱいになった場合にのみ呼び出されます。