Sekarang kita mengarahkan perangkat stream yang sudah dikuasai ke tujuan yang paling penting: file di disk. Header <fstream> menyediakan tiga kelas yang menempel persis pada peta dari Chapter Peta iostream — std::ofstream untuk menulis, std::ifstream untuk membaca, dan std::fstream untuk keduanya. Karena ketiganya turunan ostream/istream, seluruh operator <</>>, manipulator, dan pola yang kita latih berlaku tanpa penyesuaian. Yang benar-benar baru hanyalah dua hal: cara membuka file beserta mode-nya, dan jaminan penutupan otomatis lewat RAII.
Tiga Kelas File Stream #
| Kelas | Arah | Mode bawaan | Setara stream lain |
|---|---|---|---|
std::ofstream | Program → file | ios::out | ios::trunc | Seperti cout, tujuannya file |
std::ifstream | File → program | ios::in | Seperti cin, sumbernya file |
std::fstream | Dua arah | ios::in | ios::out | Gabungan keduanya |
Sebuah ofstream bukan “perintah tulis file” melainkan objek stream yang bertahan — ia membuka file saat dikonstruksi (atau saat open() dipanggil), menjaga file tetap terhubung selama hidup, lalu menutupnya saat objek hancur. Pola hidup-mati objek ini yang membuat penanganan file di C++ terasa rapi dibanding membuka-menutup manual.
Menulis, Menambah, dan Membaca Kembali #
Program berikut melakukan siklus lengkap dalam satu file: menulis dua baris ke file baru, menambah satu baris dengan mode append, lalu membaca seluruh isinya kembali:
#include <fstream>
#include <iostream>
#include <string>
int main() {
// 1. Tulis file baru (mode bawaan: ios::out | ios::trunc)
{
std::ofstream tulis("catatan.txt");
if (!tulis.is_open()) {
std::cerr << "Gagal membuka catatan.txt untuk ditulis\n";
return 1;
}
tulis << "Belajar fstream hari ini\n";
tulis << "RAII menutup file otomatis\n";
} // destructor ofstream: file tertutup dan ter-flush
// 2. Tambah satu baris (mode app = append)
{
std::ofstream tambah("catatan.txt", std::ios::app);
if (!tambah.is_open()) {
std::cerr << "Gagal membuka file untuk append\n";
return 1;
}
tambah << "Baris tambahan lewat mode app\n";
}
// 3. Baca seluruh isi kembali
std::ifstream baca("catatan.txt");
if (!baca.is_open()) {
std::cerr << "Gagal membuka catatan.txt untuk dibaca\n";
return 1;
}
std::cout << "Isi catatan.txt:\n";
std::string baris;
while (std::getline(baca, baris)) {
std::cout << " " << baris << '\n';
}
return 0;
}Output yang Dihasilkan:
Isi catatan.txt:
Belajar fstream hari ini
RAII menutup file otomatis
Baris tambahan lewat mode app- Baris 8-9 (blok kurawal + konstruksi):
std::ofstream tulis("catatan.txt")langsung membuka file. Blok{}sengaja dibuat supaya keberadaan objek ini tidak melebihi kebutuhannya. - Baris 10-12 (
is_open()): pembukaan bisa gagal — folder tidak ada, izin kurang. Hasilnya bukan program mati melainkan state gagal, danis_open()adalah pemeriksa pertama yang wajib. - Baris 15-16 (
tulis << ...): penulisan terasa sama persis dengancout; karakternya diantrikan di buffer stream. - Baris 18 (akhir blok):
tulishancur di sini, dan destructor-nya menutup file sekaligus mengosongkan buffer. Tanpa satu barisclose()pun, data sudah aman di disk — inilah RAII yang dipelajari pada Section Pemrograman Berorientasi Objek bekerja pada resource nyata. - Baris 21-22 (mode app): pembukaan kedua memakai
std::ios::app, sehingga file yang sama tidak di-trunc; baris baru ditambahkan di ujung. - Baris 30-31 (
getlineloop): pembacaan kembali memakai pola yang akan kita bedah tuntas pada Chapter berikutnya — selamagetlineberhasil, satu baris masuk kebaris.
Mode Pembukaan #
Parameter kedua konstruktor (dan open()) menerima satu atau beberapa mode yang digabung dengan |:
| Mode | Arti |
|---|---|
ios::in | Buka untuk membaca; posisi awal di awal file |
ios::out | Buka untuk menulis |
ios::app | Semua tulisan selalu di ujung file (append) |
ios::trunc | Buang isi lama — file jadi kosong saat dibuka |
ios::binary | Akses per byte tanpa terjemahan karakter khusus |
Mode bawaan sudah disesuaikan per kelas: ifstream memakai in, ofstream memakai out | trunc, dan fstream memakai in | out. Kombinasi lazim yang layak dihafal: std::ios::app untuk log yang terus bertambah, std::ios::out | std::ios::app bila ingin eksplisit, dan std::ios::in | std::ios::out untuk membaca-lalu-memperbarui tanpa menghilangkan isi. Perbedaan app dan out | app detailnya halus; untuk pemula, gunakan app saja saat maksudnya menambah.
is_open dan Jaminan RAII #
is_open() mengembalikan true hanya bila file benar-benar terhubung dengan stream. Kegagalan membuka juga menyalakan failbit, sehingga if (!tulis) sama informatifnya dengan if (!tulis.is_open()) — pilih salah satu gaya dan konsisten. Pemeriksaan di atas punya alasan penting: std::fstream secara bawaan tidak melempar exception saat gagal membuka, jadi pemeriksaan manual adalah satu-satunya alarm.
Sedikit tentang penutupan: kita bisa memanggil out.close() eksplisit, dan itu perlu dalam kasus jarang — misalnya ingin memakai ulang objek yang sama untuk file lain, atau memastikan file tertutup sebelum mengganti namanya. Di luar itu, biarkan RAII bekerja: file otomatis tertutup tepat ketika objek keluar dari scope, urutannya terbalik dengan pembukaan bila ada banyak stream terbuka, dan tidak ada jalur eksekusi — termasuk return di tengah fungsi atau exception — yang bisa lolos melewatinya.
Fondasi file kita sudah berdiri: buka, tulis, tambah, baca, tutup. Dua chapter berikutnya memperdalam dua sisi siklus ini — membaca file teks dengan pola yang benar, lalu menulisnya dengan aman.