Berkas teks dan encoding

Membaca berkas teks dengan mode open, disiplin utf-8, dan iterasi per baris.

Daftar isi

Berkas teks adalah salah satu sumber data yang paling sering dibaca oleh program, mulai dari catatan sederhana hingga data hasil ekspor aplikasi lain. Topik ini membahas fungsi open() beserta mode bacanya, disiplin penulisan encoding="utf-8", dan cara mengiterasi berkas per baris. Setelah membacanya, berkas teks dapat dibaca dan ditulis secara andal tanpa bergantung pada pengaturan platform tempat program dijalankan.

Membaca berkas dengan open dan with#

Fungsi open() menerima jalur berkas dan mode sebagai argumen utamanya, lalu mengembalikan file object, yaitu objek perantara yang menyediakan seluruh operasi baca dan tulis. Mode "r" (baca) dipakai untuk membaca dan merupakan mode bawaan apabila argumen mode ditinggalkan. Karena berkas terbuka adalah sumber daya sistem operasi yang jumlahnya terbatas, pemanggilan open() selalu dibungkus pernyataan with agar berkas ditutup secara otomatis setelah bloknya selesai.

python baca-surat.py
from pathlib import Path

Path("surat.txt").write_text("Halo\nDunia\n", encoding="utf-8")

with open("surat.txt", encoding="utf-8") as f:
    isi = f.read()
print(isi, end="")
text Keluaran
Halo
Dunia

Metode read() mengembalikan seluruh isi berkas sebagai satu string. Baris pertama pada contoh membuat berkas contoh terlebih dahulu, sehingga program dapat dijalankan berulang kali tanpa menyiapkan berkas secara manual. Argumen encoding="utf-8" diberikan secara eksplisit, dan alasan pentingnya dijelaskan pada bagian tersendiri. Setelah blok with berakhir, berkas sudah tertutup, dan pemanggilan read() lagi pada objek yang sama ditolak dengan error ValueError.

Mode pada open() menentukan perilaku tulisnya. Mode "w" (tulis) membuka berkas untuk ditulis dan mengosongkannya begitu dibuka, sedangkan mode "a" (tambah) menyisipkan teks baru di akhir berkas tanpa menyentuh isinya. Kedua mode tersebut membuat berkas baru secara otomatis apabila berkas yang dimaksud belum ada, sehingga penyiapan berkas kosong tidak diperlukan.

python Contoh: mode w lalu mode a pada berkas yang sama
with open("log-tes.txt", "w", encoding="utf-8") as f:
    f.write("baris pertama\n")
    f.write("baris kedua\n")

with open("log-tes.txt", "a", encoding="utf-8") as f:
    f.write("baris ketiga\n")

with open("log-tes.txt", encoding="utf-8") as f:
    print(f.read(), end="")
text Keluaran
baris pertama
baris kedua
baris ketiga

Metode write() tidak menambahkan tanda baris baru secara otomatis, sehingga karakter \n ditempatkan secara manual di akhir setiap baris. Apabila mode "a" pada pembukaan kedua diganti menjadi "w", isi berkas akan menyusut menjadi satu baris karena mode tersebut mengosongkan berkas sejak awal. Perilaku ini sering luput dari perhatian ketika program menulis ke berkas yang sama berulang kali dalam satu proses yang panjang.

Iterasi per baris#

Objek berkas teks dapat diiterasi seperti sekuens, dan setiap putaran menghasilkan satu baris lengkap dengan tanda \n di ujungnya. Pola ini lebih hemat memori daripada read() karena seluruh isi tidak perlu dimuat sekaligus, sehingga cocok untuk berkas berukuran besar. Metode rstrip() dipakai untuk membuang tanda baris baru beserta spasi di ujung baris sebelum baris tersebut dicetak.

python Contoh: iterasi berkas baris demi baris
with open("sekolah.txt", "w", encoding="utf-8") as f:
    f.write("SD Amanatul Ummah\nSD Negeri 01\nSMP Negeri 3\n")

with open("sekolah.txt", encoding="utf-8") as f:
    for nomor, baris in enumerate(f, start=1):
        print(nomor, baris.rstrip())
text Keluaran
1 SD Amanatul Ummah
2 SD Negeri 01
3 SMP Negeri 3

Fungsi enumerate() menyediakan nomor baris yang dimulai dari 1 melalui argumen start. Metode readlines() juga tersedia dan mengembalikan seluruh baris sebagai list, tetapi perulangan langsung atas objek berkas tetap lebih disukai untuk berkas besar karena tidak menumpuk semuanya di memori. Satu perbedaan yang penting diperhatikan adalah iterator berkas hanya dapat digunakan satu kali, sehingga perulangan kedua pada objek berkas yang sama tidak lagi menghasilkan baris apa pun.

Disiplin encoding utf-8#

Encoding adalah aturan pemetaan antara karakter dan rangkaian byte, dan satu berkas teks pada dasarnya hanyalah byte yang menunggu ditafsirkan. Apabila argumen encoding ditinggalkan, Python memakai encoding bawaan platform, dan nilainya berbeda antar sistem operasi, sehingga program yang berjalan baik di satu mesin dapat rusak di mesin lainnya. Karena itu, setiap pemanggilan open() untuk berkas teks pada jalur ini selalu menyertakan encoding="utf-8" sebagai kebiasaan baku.

python Contoh: error ketika encoding tidak cocok
teks = "kopi à 25 ribu\n"
with open("menu.txt", "wb") as f:
    f.write(teks.encode("utf-8"))

try:
    with open("menu.txt", encoding="ascii") as f:
        f.read()
except UnicodeDecodeError as e:
    print(type(e).__name__)

with open("menu.txt", encoding="utf-8") as f:
    print(f.read(), end="")
text Keluaran
UnicodeDecodeError
kopi à 25 ribu

Mode "wb" menulis byte mentah tanpa penafsiran apa pun, dan byte yang sama kemudian dibaca dengan dua encoding yang berbeda. Encoding ascii menolak karakter à karena bukan anggotanya, sehingga error UnicodeDecodeError muncul, sedangkan utf-8 membaca byte yang sama dengan benar. Error semacam ini selalu berarti byte berkas dan encoding yang diberikan tidak sepakat, bukan berarti berkasnya rusak.

Kesalahan umum#

Kesalahan pertama adalah membuka berkas yang isinya masih dibutuhkan dengan mode "w". Isi lama hilang pada saat open() dijalankan, jauh sebelum satu karakter pun ditulis, dan tidak ada mekanisme pemulihan pada level open(). Perbaikannya adalah menulis ke berkas sementara terlebih dahulu, lalu menggantikan berkas aslinya setelah penulisan selesai, atau memakai mode "a" bila isi lama memang ingin dipertahankan.

Kesalahan kedua adalah mengiterasi objek berkas yang sama dua kali tanpa membukanya ulang. Iterator berkas habis setelah putaran pertama, sehingga hasilnya tampak kosong tanpa pesan error apa pun.

python Contoh: iterator berkas hanya berlaku satu kali
with open("sekolah.txt", encoding="utf-8") as f:
    print(len(list(f)))
    print(len(list(f)))
text Keluaran
3
0

Perbaikannya adalah membuka berkas kembali pada perulangan berikutnya, atau memanggil f.seek(0) untuk mengembalikan posisi baca ke awal berkas. Kesalahan ketiga adalah meninggalkan argumen encoding dengan alasan programnya sudah berjalan baik. Pada platform dengan encoding bawaan yang berbeda, teks sama dapat menghasilkan karakter rusak atau error UnicodeDecodeError, sehingga argumen tersebut tetap ditulis eksplisit di semua tempat.

Ringkasan#

  • open() di dalam blok with membuka dan menutup berkas secara deterministik, sedangkan mode "r", "w", dan "a" menentukan perilaku baca, tulis, dan tambah.
  • Metode read() memuat seluruh isi sekaligus, sedangkan iterasi langsung atas objek berkas memproses satu baris per putaran dan lebih hemat memori.
  • Argumen encoding="utf-8" ditulis eksplisit agar perilaku program sama pada semua platform.
  • UnicodeDecodeError menandakan byte berkas tidak cocok dengan encoding yang diberikan saat membaca.

Referensi#