File I/O di C++ dibangun di atas sistem stream yang sama dengan cin/cout — jika kamu sudah familiar dengan output ke konsol, membaca dan menulis file menggunakan mekanisme yang sangat serupa. C++ menggunakan pola RAII (dari artikel exception handling) untuk memastikan file selalu ditutup dengan benar, bahkan saat terjadi exception.
Tiga Kelas Utama
| Kelas | Header | Kegunaan |
|---|---|---|
ifstream | <fstream> | Membaca file (input) |
ofstream | <fstream> | Menulis file (output) |
fstream | <fstream> | Baca dan tulis sekaligus |
Menulis ke File dengan ofstream
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main() {
// Buka file untuk menulis — RAII: file ditutup otomatis saat scope berakhir
ofstream file("catatan.txt");
if (!file.is_open()) {
cerr << "Gagal membuka file untuk menulis!" << endl;
return 1;
}
// Menulis seperti cout
file << "Baris pertama" << endl;
file << "Baris kedua" << endl;
file << "Angka: " << 42 << ", Pi: " << 3.14 << endl;
// file.close() dipanggil otomatis saat keluar scope
cout << "File berhasil ditulis." << endl;
return 0;
}
Mode Pembukaan File
#include <fstream>
#include <iostream>
using namespace std;
int main() {
// ios::out — menulis (default untuk ofstream), hapus isi lama
// ios::app — append: tambah di akhir tanpa hapus isi lama
// ios::in — membaca (default untuk ifstream)
// ios::binary — mode binary (untuk file gambar, dll.)
// ios::trunc — hapus isi file saat dibuka (default bersama ios::out)
// Append ke file yang sudah ada
{
ofstream log("app.log", ios::app);
log << "[INFO] Aplikasi dijalankan" << endl;
}
{
ofstream log("app.log", ios::app);
log << "[INFO] Proses selesai" << endl;
}
// Buka untuk baca DAN tulis
{
fstream rw("data.txt", ios::in | ios::out | ios::app);
rw << "Tambahan data" << endl;
// Kembali ke awal untuk membaca
rw.seekg(0, ios::beg);
string baris;
while (getline(rw, baris)) {
cout << baris << endl;
}
}
return 0;
}
Membaca File dengan ifstream
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main() {
ifstream file("catatan.txt");
if (!file.is_open()) {
cerr << "File tidak ditemukan!" << endl;
return 1;
}
// Cara 1: Baca baris per baris dengan getline
string baris;
int nomor = 1;
while (getline(file, baris)) {
cout << nomor++ << ": " << baris << endl;
}
// Kembali ke awal file
file.clear(); // Reset error flag (eof)
file.seekg(0, ios::beg);
// Cara 2: Baca kata per kata (dipisah whitespace)
string kata;
while (file >> kata) {
cout << "[" << kata << "] ";
}
cout << endl;
// Cara 3: Baca seluruh isi sekaligus
file.clear();
file.seekg(0, ios::beg);
string isi_penuh((istreambuf_iterator<char>(file)),
istreambuf_iterator<char>());
cout << "Seluruh isi:\n" << isi_penuh << endl;
return 0;
}
stringstream — Parsing Teks dalam Memori
stringstream sangat berguna untuk memparse baris teks:
#include <sstream>
#include <iostream>
#include <string>
using namespace std;
int main() {
string baris = "Ali Akbar 25 Developer";
istringstream ss(baris); // istringstream: stream dari string
string nama_depan, nama_belakang, jabatan;
int umur;
ss >> nama_depan >> nama_belakang >> umur >> jabatan;
cout << "Nama: " << nama_depan << " " << nama_belakang << endl;
cout << "Umur: " << umur << endl;
cout << "Jabatan: " << jabatan << endl;
// Output:
// Nama: Ali Akbar
// Umur: 25
// Jabatan: Developer
// ostringstream: buat string dari berbagai tipe
ostringstream hasil;
hasil << "Harga: Rp " << 15000000 << " (diskon " << 10.5 << "%)";
string pesan = hasil.str();
cout << pesan << endl;
// Output: Harga: Rp 15000000 (diskon 10.5%)
return 0;
}
Praktik: Membaca dan Menulis CSV
#include <fstream>
#include <sstream>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
struct Mahasiswa {
string nama;
int nim;
double nilai;
};
// Tulis data mahasiswa ke CSV
void tulis_csv(const string& filename, const vector<Mahasiswa>& data) {
ofstream file(filename);
if (!file.is_open()) throw runtime_error("Gagal membuka file: " + filename);
file << "nama,nim,nilai" << endl; // Header
for (const auto& m : data) {
file << m.nama << "," << m.nim << "," << m.nilai << "\n";
}
cout << "Data disimpan ke " << filename << endl;
}
// Baca CSV dan kembalikan vector mahasiswa
vector<Mahasiswa> baca_csv(const string& filename) {
ifstream file(filename);
if (!file.is_open()) throw runtime_error("File tidak ditemukan: " + filename);
vector<Mahasiswa> hasil;
string baris;
getline(file, baris); // Lewati header
while (getline(file, baris)) {
if (baris.empty()) continue;
istringstream ss(baris);
string tok;
Mahasiswa m;
getline(ss, m.nama, ',');
getline(ss, tok, ','); m.nim = stoi(tok);
getline(ss, tok, ','); m.nilai = stod(tok);
hasil.push_back(m);
}
return hasil;
}
int main() {
// Tulis data
vector<Mahasiswa> mahasiswa = {
{"Budi Santoso", 2021001, 85.5},
{"Siti Aminah", 2021002, 92.0},
{"Ahmad Fauzi", 2021003, 78.3},
};
tulis_csv("mahasiswa.csv", mahasiswa);
// Baca kembali
auto data = baca_csv("mahasiswa.csv");
cout << "\nData mahasiswa:" << endl;
double total = 0;
for (const auto& m : data) {
cout << m.nama << " (NIM: " << m.nim << ") — Nilai: " << m.nilai << endl;
total += m.nilai;
}
cout << "Rata-rata: " << total / data.size() << endl;
// Output:
// Data mahasiswa:
// Budi Santoso (NIM: 2021001) — Nilai: 85.5
// Siti Aminah (NIM: 2021002) — Nilai: 92
// Ahmad Fauzi (NIM: 2021003) — Nilai: 78.3
// Rata-rata: 85.2667
return 0;
}
Pertanyaan yang Sering Diajukan
Apakah perlu memanggil file.close() secara manual?
Tidak perlu jika file dideklarasikan sebagai variabel lokal — destruktor ifstream/ofstream akan memanggil close() secara otomatis saat variabel keluar scope (RAII). Namun, ada situasi di mana memanggil close() manual berguna: ketika ingin memastikan data di-flush ke disk sebelum dibaca program lain, atau saat perlu membuka ulang file yang sama dengan mode berbeda di scope yang sama.
Mengapa file.clear() diperlukan sebelum seekg()?
Saat membaca sampai akhir file, ifstream mengeset flag eofbit. Jika kamu langsung memanggil seekg() tanpa clear() terlebih dahulu, operasi seek akan gagal karena stream dalam state error. clear() mereset semua flag error sehingga stream bisa digunakan kembali.
Apa perbedaan getline() dan operator >>?
Operator >> membaca sampai whitespace (spasi, tab, newline) — tidak bisa membaca kalimat yang mengandung spasi. getline(stream, string) membaca sampai newline termasuk spasi di dalamnya. getline(stream, string, delimiter) membaca sampai karakter delimiter tertentu — sangat berguna untuk parsing CSV. Untuk data teks biasa, getline lebih fleksibel.
Bagaimana cara menangani file yang tidak ada?
Selalu periksa file.is_open() setelah membuka file. Jika false, file tidak ada atau tidak bisa diakses (izin tidak cukup). Untuk aplikasi yang robust, lempar exception dengan pesan yang jelas (seperti contoh tulis_csv), atau gunakan std::filesystem::exists() (C++17) untuk memeriksa keberadaan file sebelum membukanya.
Kesimpulan
| Operasi | C++ | C# | Java |
|---|---|---|---|
| Baca file | ifstream + getline | File.ReadAllText / StreamReader | BufferedReader / Files.readAllLines |
| Tulis file | ofstream + << | File.WriteAllText / StreamWriter | BufferedWriter / Files.write |
| Append | ios::app flag | FileMode.Append | FileWriter(path, true) |
| Resource cleanup | RAII (destructor) | using statement | try-with-resources |
| Parse teks | istringstream | string.Split | Scanner / split |
Artikel sebelumnya: Exception Handling di C++ — try/catch dan RAII.
Selamat! Kamu sudah menguasai fondasi C++ dari variabel hingga file I/O. Untuk memperluas kemampuan, pelajari Data Structures — fondasi algoritma yang menggunakan C++ sebagai contoh.