Setiap data yang perlu bertahan setelah program berakhir disimpan dalam berkas, dan pintu masuk operasi berkas di C adalah pasangan fungsi fopen dan fclose. Topik ini membahas cara membuka serta menutup berkas dan makna setiap mode pada argumen kedua fopen. Kemudian dibahas variasi baca tulis dengan tanda +, perbedaan mode teks dan mode biner, serta pemeriksaan kegagalan yang wajib dilakukan setiap kali berkas dibuka. Setelah membacanya, berkas teks dapat dibuat, dibaca, ditambah, dan diperbarui dengan pola yang benar.
Membuka dan menutup berkas#
Fungsi fopen pada stdio.h membuka berkas dan mengembalikan pointer bertipe FILE *. Pointer itu menjadi pegangan menuju stream, yakni saluran data yang dikelola pustaka standar. Lewat mekanisme yang sama, program membaca keyboard, menulis ke layar, dan mengakses berkas dengan fungsi yang seragam. Argumen pertama fopen berupa nama berkas, sedangkan argumen kedua berupa teks mode seperti "r" yang menentukan arah aksesnya. Pointer FILE * yang dihasilkan menjadi argumen pertama bagi hampir semua fungsi I/O berkas lainnya.
Program berikut membuat berkas harian.txt, menulis satu baris ke dalamnya, lalu menutupnya. Pola buka, gunakan, tutup inilah kerangka dasar seluruh operasi berkas:
#include <stdio.h>
int main(void) {
FILE *berkas = fopen("harian.txt", "w");
if (berkas == NULL) {
perror("fopen harian.txt");
return 1;
}
fputs("Suhu pagi 27.5\n", berkas);
fclose(berkas);
printf("harian.txt berhasil dibuat.\n");
return 0;
}harian.txt berhasil dibuat.Pemeriksaan berkas == NULL ditempatkan sebelum pointer dipakai untuk apa pun, sehingga tidak ada penulisan yang ditujukan ke stream yang tidak ada. Fungsi fputs, yang menulis satu teks ke stream, hanya disinggung di sini dan dibahas tuntas pada topik I/O Teks. Fungsi fclose menutup stream serta membebaskan sumber daya yang terpakai, dan pemanggilannya menjamin data yang masih tertahan di buffer benar-benar tiba pada berkas. Apabila program berakhir tanpa menutup berkasnya, sebagian tulisan berpotensi hilang karena buffer belum disiram.
Pemeriksaan kegagalan fopen#
Fungsi fopen mengembalikan NULL setiap kali berkas gagal dibuka, dan kegagalan itu bukan hal langka. Mode "r" gagal bila berkasnya belum ada, akses dapat ditolak karena izin berkas, jalur bisa berupa direktori alih-alih berkas, dan disk dapat penuh saat mode menulis. Pointer NULL yang tidak diperiksa membuat program berhenti mendadak begitu dipakai memanggil fungsi I/O, sehingga pemeriksaan ini wajib pada setiap pemanggilan fopen. Contoh berikut mencoba membuka berkas yang memang tidak ada:
#include <stdio.h>
int main(void) {
FILE *berkas = fopen("arsip-tidak-ada.txt", "r");
if (berkas == NULL) {
perror("Buka arsip-tidak-ada.txt");
return 1;
}
fclose(berkas);
return 0;
}Buka arsip-tidak-ada.txt: No such file or directoryFungsi perror mencetak argumennya diikuti sebab kegagalan yang dilaporkan sistem, yaitu No such file or directory atau dalam istilah lain berkas tidak ditemukan. Penanganan yang lebih rinci tentang pesan error semacam ini dibahas pada topik Penanganan Error Berkas di akhir modul. Untuk saat ini, kebiasaan yang perlu terbentuk hanya satu, yaitu pointer FILE * tidak pernah dipakai sebelum lolos pemeriksaan NULL. Nilai kembali 1 pada return juga memberi tahu shell bahwa program berakhir karena kegagalan, bukan karena sukses.
Mode dasar r, w, dan a#
Argumen mode menentukan dua hal sekaligus, yaitu arah akses dan akibatnya pada isi berkas yang sudah ada. Mode "r" hanya membaca dan menuntut berkasnya tersedia, mode "w" menulis dengan mengosongkan isi lama, sedangkan mode "a" menulis dengan menempelkan data di ujung berkas. Tabel berikut merangkum perilaku ketiganya:
| Mode | Berkas boleh baru | Posisi awal penulisan | Isi lama |
|---|---|---|---|
"r" | tidak | tidak ada penulisan | utuh, hanya dibaca |
"w" | ya | awal berkas | dikosongkan sejak awal |
"a" | ya | ujung berkas | utuh, tulisan menempel di ujung |
Perilaku "w" dan "a" terlihat jelas pada program yang membuka berkas yang sama dua kali dengan mode berbeda:
#include <stdio.h>
int main(void) {
/* mode "w": berkas dibuat baru, isi lama dikosongkan */
FILE *berkas = fopen("rekap.txt", "w");
if (berkas == NULL) {
perror("fopen rekap.txt");
return 1;
}
fputs("Baris satu\n", berkas);
fclose(berkas);
/* mode "a": tulisan baru menempel di ujung berkas */
berkas = fopen("rekap.txt", "a");
if (berkas == NULL) {
perror("fopen rekap.txt");
return 1;
}
fputs("Baris dua\n", berkas);
fclose(berkas);
printf("rekap.txt kini berisi dua baris.\n");
return 0;
}rekap.txt kini berisi dua baris.# kompilasi dan jalankan program
gcc demo-mode.c -o demo-mode && ./demo-mode
# tampilkan isi rekap.txt
cat rekap.txtrekap.txt kini berisi dua baris.
Baris satu
Baris duaTahap pertama membuat rekap.txt berisi Baris satu, sedangkan tahap kedua menambahkan Baris dua tanpa merusak baris yang sudah ada. Diagram berikut merangkum akibat ketiga mode terhadap isi berkas:
Memperbarui berkas dengan tanda +#
Tanda + pada mode membuka dua arah sekaligus, yaitu baca dan tulis pada stream yang sama. Mode "r+" mempertahankan isi berkas dan memulai di posisi awal, mode "w+" mengosongkan berkas lebih dahulu, sedangkan mode "a+" mengizinkan pembacaan dari posisi mana pun. Setiap penulisan pada mode "a+" selalu menuju ujung berkas. Tabel berikut meringkas ketiganya:
| Mode | Baca | Tulis | Isi lama |
|---|---|---|---|
"r+" | ya | ya, dari posisi saat ini | utuh |
"w+" | ya | ya, dari awal | dikosongkan |
"a+" | ya | selalu di ujung | utuh |
Mode "r+" paling sering digunakan untuk memperbarui catatan secara langsung. Program berikut menyusun berkas stok.txt, lalu menimpa catatan pertamanya tanpa menyentuh baris lain. Program ini sengaja tidak mencetak apa pun, sehingga hasilnya diperiksa lewat perintah cat:
#include <stdio.h>
int main(void) {
/* susun berkas awal berisi dua catatan */
FILE *berkas = fopen("stok.txt", "w");
if (berkas == NULL) {
perror("fopen stok.txt");
return 1;
}
fputs("Ali 90\n", berkas);
fputs("Budi 75\n", berkas);
fclose(berkas);
/* mode "r+": timpa catatan pertama tanpa menghapus sisanya */
berkas = fopen("stok.txt", "r+");
if (berkas == NULL) {
perror("fopen stok.txt");
return 1;
}
fputs("Dewi 82\n", berkas);
fclose(berkas);
return 0;
}# kompilasi dan jalankan program pembaruan
gcc rplus.c -o rplus && ./rplus
# tampilkan isi stok.txt setelah diperbarui
cat stok.txtDewi 82
Budi 75Penulisan pada mode "r+" bekerja seperti menimpa byte pada posisi penunjuk saat ini, sehingga teks Dewi 82 menggantikan Ali 90 yang berukuran sama persis. Perhatikan bahwa jumlah karakter teks pengganti wajib pas, karena byte yang lebih panjang akan menimpa baris berikutnya. Teknik bergerak ke catatan tertentu sebelum menulis dibahas lebih lanjut pada topik Akses Acak.
Mode teks dan mode biner#
Akhiran b pada mode, misalnya "rb", "wb", "ab", dan "r+b", memilih mode biner alih-alih mode teks. Pada mode teks, pustaka standar boleh menerjemahkan penanda baris sesuai konvensi platform, misalnya mengubah \n menjadi dua byte pada Windows. Mode biner meneruskan byte apa adanya, tanpa terjemahan apa pun. Data yang bukan teks, seperti gambar atau hasil fwrite, wajib dibuka dalam mode biner agar tidak berubah oleh penerjemahan itu. Perbedaan mode teks dan biner dibedah lebih jauh pada topik I/O Biner.
Kebiasaan yang baik adalah memilih mode berdasarkan isi berkas, bukan berdasarkan kebiasaan menulis. Berkas teks yang dibaca per baris cukup menggunakan mode teks, sedangkan berkas data mentah menggunakan mode biner sejak awal. Tuliskan salah satu gaya secara konsisten, misalnya selalu "r+b" atau selalu "rb+", karena keduanya bermakna sama dan pustaka standar menerima keduanya.
Kesalahan umum#
Kesalahan pertama adalah mengharapkan mode "r" membuat berkas yang belum ada. Mode "r" murni untuk membaca, sehingga fopen pada berkas yang tidak ada selalu menghasilkan NULL. Program yang mengandalkan mode ini tampak tidak berjalan, padahal penyebabnya justru pemilihan mode. Berkas baru dibuat dengan mode "w" atau "a", sedangkan "r" disediakan untuk berkas yang sudah tersedia.
Kesalahan kedua adalah membuka berkas penting dengan "w" karena sudah terbiasa memakai mode tersebut. Isi lama terhapus begitu fopen berhasil, sehingga berkas log atau data lama yang seharusnya ditambah malah kosong. Gunakan "a" untuk menulis berkas yang isinya terus bertambah, dan simpan mode "w" untuk berkas yang memang diciptakan dari nol.
Kesalahan ketiga adalah lupa memanggil fclose. Buffer keluaran belum tentu tersiram, tulisan terakhir berpotensi tidak pernah tiba di berkas, dan stream yang dibiarkan terbuka menghabiskan sumber daya sistem. Tutup setiap berkas pada semua jalur eksekusi, termasuk jalur yang berakhir karena error. Penutupan oleh sistem operasi saat program berakhir bukan jaminan yang layak diandalkan.
Ringkasan#
- fopen mengembalikan
FILE *yang wajib dibandingkan denganNULLsebelum digunakan, dan fclose menutup stream sekaligus menyiram buffer tulisannya. - Mode
"r"hanya membaca berkas yang sudah ada,"w"membuat atau mengosongkan berkas, sedangkan"a"menambahkan data di ujung. - Tanda
+membuka baca dan tulis sekaligus, dengan"r+"mempertahankan isi lama dan penulisan mengikuti posisi penunjuk. - Akhiran
bmemilih mode biner yang meneruskan byte apa adanya, sedangkan mode teks boleh menerjemahkan penanda baris pada platform tertentu.
Referensi#
- fopen, fopen_s — cppreference — Dokumentasi fopen beserta tabel lengkap mode dan perilakunya.
- fclose — cppreference — Dokumentasi fclose dan nilai kembanya.
- fopen(3) — Linux manual pages — Man page fopen, fdopen, dan freopen beserta catatan mode di Linux.