Membaca atau menulis satu byte ke berkas dalam satu panggilan berarti satu permintaan ke sistem operasi — dan permintaan itu jauh lebih mahal daripada menyalin satu byte di memori. BufferedStream mengatasi ketidakefisienan ini dengan menyisipkan buffer di antara kode kita dan stream dasar: tulisan-tulisan kecil dikumpulkan dahulu, lalu dituangkan ke stream dasar sekaligus per ukuran buffer.

Cara BufferedStream Bekerja #

BufferedStream membungkus stream lain, misalnya FileStream, dan menyimpan data sementara di array internal. Ukuran buffer diset lewat constructor; pilihan bawaannya 4096 byte. Tulisan hanya mencapai stream dasar ketika buffer penuh atau saat Flush dan Dispose dipanggil. Pembacaan bekerja sebaliknya: satu permintaan ke stream dasar mengisi buffer, lalu beberapa panggilan Read berikutnya dilayani langsung dari memori.

Contoh Menulis 1000 Byte Satu per Satu #

Contoh berikut menulis seribu byte satu per satu lewat BufferedStream, lalu membacanya kembali dengan pola yang sama. Hasil akhirnya identik dengan penulisan tanpa buffer; perbedaannya ada pada jumlah permintaan yang dikirim ke stream dasar:

csharp
string dir = Path.Combine(Path.GetTempPath(), "verify-6c", "buffered-stream");
Directory.CreateDirectory(dir);
string path = Path.Combine(dir, "buffer.bin");

using (FileStream dasar = new FileStream(path, FileMode.Create, FileAccess.Write))
using (BufferedStream aliran = new BufferedStream(dasar, 4096))
{
    for (int i = 0; i < 1000; i++)
    {
        aliran.WriteByte((byte)(i % 256));
    }
}

Console.WriteLine($"Ukuran file: {new FileInfo(path).Length} byte");

using FileStream sumber = new FileStream(path, FileMode.Open, FileAccess.Read);
using BufferedStream pembaca = new BufferedStream(sumber, 4096);
int total = 0;
while (pembaca.ReadByte() != -1)
{
    total++;
}
Console.WriteLine($"Total byte terbaca: {total}");

Output yang Dihasilkan:

text
Ukuran file: 1000 byte
Total byte terbaca: 1000

Mari kita bedah baris demi baris:

  1. Dua using bertumpuk: BufferedStream membungkus FileStream, sehingga setiap WriteByte mengisi buffer, bukan langsung ke disk.
  2. Seribu panggilan WriteByte: karena buffer 4096 byte belum penuh, seluruh tulisan menunggu di memori hingga blok using berakhir.
  3. Dispose di akhir blok: menuangkan sisa 1000 byte ke FileStream dalam satu pengecoran, lalu FileInfo.Length membuktikan ukuran berkas tepat 1000 byte.
  4. Perulangan ReadByte: setiap byte dilayani dari buffer; ReadByte mengembalikan -1 saat akhir aliran tercapai, sehingga penghitung berhenti dengan benar.