Episode ini membahas pengelolaan file di C#: System.IO dengan File, Directory, dan Path, penggunaan stream seperti StreamReader, StreamWriter, dan FileStream, serialisasi JSON dan XML dengan System.Text.Json, serta pola asynchronous I/O dengan async/await.

Sebagian besar aplikasi nyata membaca atau menulis data ke luar memori: file konfigurasi, log, data ekspor, atau cache. Mengelola operasi I/O dengan benar adalah keterampilan yang membedakan aplikasi yang tahan lama dari aplikasi yang mudah rusak.
Masalah yang paling sering muncul adalah resource yang tidak dibebaskan, path yang dihardcode, dan operasi sinkron yang memblokir thread saat menunggu disk. Ketiganya bisa dihindari dengan pola yang benar.
Episode 7 ini membahas API System.IO, stream untuk membaca dan menulis data besar, serialisasi JSON dan XML, serta konsep asynchronous I/O yang akan kalian pakai di hampir semua aplikasi web. Semua kode di episode ini bisa dijalankan langsung dengan dotnet run.
Namespace System.IO menyediakan kelas statis File, Directory, dan Path untuk operasi umum:
var jalur = Path.Combine("data", "catatan.txt");
Directory.CreateDirectory("data");
File.WriteAllText(jalur, "Halo dari C#\n");
var isi = File.ReadAllText(jalur);
Console.WriteLine(isi);
foreach (var file in Directory.EnumerateFiles("data"))
{
Console.WriteLine(Path.GetFileName(file));
}Perhatikan penggunaan Path.Combine("data", "catatan.txt") — jangan menyusun path secara manual dengan tanda slash, karena pemisah path berbeda antara Linux dan Windows. Path.Combine menangani keduanya secara otomatis.
Untuk file besar, membaca seluruh isi ke memori sekali jalan tidak efisien. Stream memproses data secara bertahap. StreamReader dan StreamWriter menyediakan pembacaan per baris:
using var writer = new StreamWriter("log.txt");
for (var i = 1; i <= 100; i++)
{
await writer.WriteLineAsync($"Baris ke-{i}");
}
using var reader = new StreamReader("log.txt");
while (await reader.ReadLineAsync() is { } baris)
{
Console.WriteLine(baris);
}Method WriteLineAsync dan ReadLineAsync berjalan asynchronous, sehingga thread tidak terblokir saat menunggu disk. Blok using menjamin stream ditutup meskipun terjadi error.
Untuk file biner seperti gambar atau arsip, gunakan FileStream langsung dengan buffer byte:
using var sumber = File.OpenRead("foto.jpg");
using var tujuan = File.Create("salinan.jpg");
await sumber.CopyToAsync(tujuan);CopyToAsync memindahkan data dalam potongan-potongan, meminimalkan penggunaan memori bahkan untuk file besar.
JSON adalah format pertukaran data paling umum di ekosistem modern. System.Text.Json adalah serializer bawaan yang cepat dan tanpa dependency tambahan:
record Produk(string Nama, decimal Harga, bool Tersedia);
var produk = new Produk("Kopi Gayo", 85_000m, true);
var json = JsonSerializer.Serialize(produk);
Console.WriteLine(json);
var kembali = JsonSerializer.Deserialize<Produk>(json);
Console.WriteLine(kembali!.Nama);Outputnya berupa {"Nama":"Kopi Gayo","Harga":85000,"Tersedia":true}. JsonSerializer.Deserialize<Produk>(json) mengubah JSON kembali menjadi object — pola yang dipakai di hampir semua API modern.
Untuk format XML, .NET menyediakan XmlSerializer yang memetakan class ke elemen XML:
var serializer = new XmlSerializer(typeof(Produk));
using var stream = new StringWriter();
serializer.Serialize(stream, produk);
Console.WriteLine(stream.ToString());XML masih dominan di dunia enterprise untuk integrasi sistem lama. Dengan XmlSerializer, objek C# yang sama bisa diekspor ke kedua format.
Operasi I/O memakan waktu jauh lebih lama dibanding komputasi CPU. Tanpa async, thread aplikasi terblokir menunggu — fatal untuk web server yang melayani banyak permintaan. Pola async mengembalikan kontrol ke caller sambil menunggu:
async Task<string> BacaFileAsync(string jalur)
{
return await File.ReadAllTextAsync(jalur);
}
var isi = await BacaFileAsync("data/konfigurasi.txt");
Console.WriteLine(isi);Method async Task menandakan operasi asynchronous, dan await menunggu hasil tanpa memblokir thread. Aturan penting: gunakan akhiran Async pada nama method, dan jangan blokir dengan .Result — gunakan await di seluruh rantai pemanggilan. Detail concurrency akan kita dalami di episode 14.
Inti yang harus dibawa pulang:
Path.Combine dan Directory.CreateDirectory untuk path yang aman.using menjamin pembebasan resource.FileStream.CopyToAsync menyalin file besar dengan memori minim.System.Text.Json adalah serializer JSON bawaan tanpa dependency.Di episode 8 selanjutnya kita mengatur perilaku aplikasi tanpa mengubah kode: configuration dan environment management — appsettings.json dan environment variables, options pattern, secrets management, dan .NET Generic Host dengan IHostEnvironment.