Method File.ReadAllText nyaman dipakai, tetapi seluruh isi berkas harus berada di memori terlebih dahulu. Ketika berkas berukuran gigabyte atau data mengalir dari sumber lain seperti jaringan, kita membutuhkan abstraksi yang lebih umum: stream. Stream adalah aliran byte yang bisa dibaca atau ditulis sepotong demi sepotong, dan abstraksi inilah fondasi seluruh operasi I/O di .NET.

Hierarki Stream di System IO #

Class abstrak System.IO.Stream mendefinisikan kontrak baca-tulis byte melalui method seperti Read, Write, dan Seek. Turunannya spesifik menurut sumber data, sedangkan StreamReader dan StreamWriter menyambung di atas stream untuk menerjemahkan byte menjadi karakter melalui encoding tertentu, dengan UTF-8 sebagai pilihan bawaan:

ClassPeran
FileStreamStream untuk berkas di disk
MemoryStreamStream yang tersimpan di memori
NetworkStreamStream untuk koneksi jaringan
StreamReaderPembungkus stream menjadi baris teks

Membaca Baris dengan StreamReader #

Contoh berikut membaca berkas tiga baris satu per satu, tanpa memuat seluruh isi menjadi array:

csharp
string dir = Path.Combine(Path.GetTempPath(), "verify-6c", "stream-dan-streamreader");
Directory.CreateDirectory(dir);
string path = Path.Combine(dir, "menu-kedai.txt");
File.WriteAllText(path, "Kopi Gayo\nKopi Toraja\nTeh Melati");

using StreamReader pembaca = new StreamReader(path);
string? baris;
int nomor = 1;
while ((baris = pembaca.ReadLine()) != null)
{
    Console.WriteLine($"{nomor}. {baris}");
    nomor++;
}

Console.WriteLine($"EndOfStream: {pembaca.EndOfStream}");

Output yang Dihasilkan:

text
1. Kopi Gayo
2. Kopi Toraja
3. Teh Melati
EndOfStream: True

Mari kita bedah baris demi baris:

  1. new StreamReader(path): membuka FileStream di balik layar dan menyiapkan buffer pembacaan UTF-8.
  2. pembaca.ReadLine(): mengembalikan satu baris tanpa karakter pemisahnya, atau null ketika akhir aliran tercapai; pola while menghentikan perulangan tepat di situ.
  3. string? baris: variabel bertipe nullable karena hasil ReadLine bisa null; pengujian != null memastikan isi hanya dipakai saat masih valid.
  4. pembaca.EndOfStream: bernilai True setelah byte terakhir terbaca, menandakan seluruh aliran sudah habis.
  5. using StreamReader: menutup stream saat blok berakhir; stream yang tidak pernah ditutup membuat berkas tetap dikunci di beberapa sistem operasi.