Seri bahasa pemrograman Python: #6 File I/O

Seri bahasa pemrograman Python: #6 File I/O

Python Pengenalan Python File I/O

File I/O (Input/Output) adalah cara program membaca data dari berkas dan menulis hasilnya kembali ke penyimpanan. Hampir semua alur kerja pengembangan atau penggunaan program, mulai dari analisis data sampai otomasi, membutuhkan File I/O yang rapi, aman, dan efisien.

2) Konsep Dasar

2.1 Path: absolut vs relatif
  • Absolut: dimulai dari akar sistem (/home/user/data.txt di Linux/macOS; C:\Users\... di Windows).
  • Relatif: relatif ke working directory saat ini (data.txt, ./data/data.txt).
2.2 Mode buka file

Metode yang biasa digunakan → open(path, mode, ...):

  • 'r': baca (gagal jika file tidak ada)
  • 'w': tulis baru (menghapus isi lama)
  • 'a': append (tambah di akhir)
  • 'x': buat baru (gagal jika sudah ada)
  • Tambahkan 'b' untuk biner (mis. 'rb', 'wb'), 't' untuk teks (default)
  • Tambahkan '+' untuk baca+tulis (mis. 'r+')
2.3 Teks vs biner
  • Teks: berisi karakter, perlu encoding (umumnya UTF-8).
  • Biner: berisi byte mentah (gambar, PDF, model ML). Jangan pakai encoding.

3) Membuka & Menutup File (Gunakan with)

Selalu gunakan context manager agar file tertutup otomatis, bahkan jika terjadi error.

# Membaca file teks
with open("catatan.txt", mode="r", encoding="utf-8") as f:
    isi = f.read()
print(isi)  # file sudah tertutup di sini

Mengapa with?

  • Menghindari resource leak.
  • Lebih ringkas dan aman ketimbang f = open(...); ...; f.close().

4) Membaca File Teks

4.1 Membaca seluruh isi
with open("puisi.txt", "r", encoding="utf-8") as f:
    teks = f.read()      # return str

Cocok untuk file kecil/menengah. Untuk file besar, baca bertahap.

4.2 Baris per baris (hemat memori)
with open("log.txt", "r", encoding="utf-8") as f:
    for baris in f:                  # iterator baris demi baris
        proses(baris.rstrip("\n"))
4.3 readline() & readlines()
with open("data.txt", "r", encoding="utf-8") as f:
    satu_baris = f.readline()        # baca satu baris
    semua_baris = f.readlines()      # list[str] -> hati-hati memori
4.4 Membaca per chunk
CHUNK = 1024 * 1024  # 1 MB
with open("besar.txt", "r", encoding="utf-8") as f:
    while True:
        potong = f.read(CHUNK)
        if not potong:
            break
        proses(potong)

5) Menulis & Menambahkan ke File

5.1 Tulis baru (overwrite)
with open("keluaran.txt", "w", encoding="utf-8") as f:
    f.write("Halo dunia!\n")
    f.writelines(["Baris 1\n", "Baris 2\n"])
5.2 Append (tambah di akhir)
with open("log.txt", "a", encoding="utf-8") as f:
    f.write("[INFO] program dijalankan\n")
5.3 Flushing & buffering
  • Tulis disimpan di buffer sebelum ke disk.
  • Gunakan f.flush() untuk paksa tulis, atau buka dengan buffering=1 (line-buffered) untuk streaming log.
  • Untuk keperluan realtime logging, pertimbangkan print(..., flush=True).

6) File Biner

6.1 Salin berkas biner
CHUNK = 1024 * 64
with open("gambar.png", "rb") as src, open("salinan.png", "wb") as dst:
    while True:
        blok = src.read(CHUNK)
        if not blok: break
        dst.write(blok)
6.2 Membaca ke bytes / bytearray
with open("model.bin", "rb") as f:
    data = f.read()        # type: bytes
    # data[0:4], len(data), dll.

Catatan: untuk struktur biner berformat, gunakan modul struct (pack/unpack).

7) Encoding & newline

7.1 Pilih UTF-8

Selalu eksplisit encoding="utf-8" untuk portabilitas. Jika file berisi karakter “aneh”, tangani kesalahan:

with open("teks_lokal.txt", "r", encoding="utf-8", errors="replace") as f:
    teks = f.read()   # karakter rusak diganti �

Opsi errors: "strict" (default), "ignore", "replace".

7.2 Newline lintas platform
  • Linux/macOS: \n, Windows: \r\n.
  • Python menormalkan otomatis pada mode teks. Untuk kontrol spesifik, gunakan newline="\n" ketika menulis.
with open("hasil.txt", "w", encoding="utf-8", newline="\n") as f:
    f.write("baris1\nbaris2\n")

8) pathlib: Cara Modern Kelola Path

pathlib lebih bersih daripada os.pathobject oriented & portabel.

from pathlib import Path

p = Path("data") / "masukan.txt"
if p.exists():
    teks = p.read_text(encoding="utf-8")
else:
    p.parent.mkdir(parents=True, exist_ok=True)
    p.write_text("awal\n", encoding="utf-8")

Operasi umum:

for file in Path("logs").glob("*.log"):
    print(file.name, file.stat().st_size, "bytes")

Path("old.txt").rename("arsip/old.txt")
Path("sementara.txt").unlink(missing_ok=True)

9) Format Data Populer

9.1 CSV: csv & DictReader/DictWriter
import csv
from pathlib import Path

# tulis
with Path("nilai.csv").open("w", encoding="utf-8", newline="") as f:
    w = csv.DictWriter(f, fieldnames=["nama","nilai"])
    w.writeheader()
    w.writerow({"nama":"Andi", "nilai":88})
    w.writerow({"nama":"Budi", "nilai":92})

# baca
with Path("nilai.csv").open("r", encoding="utf-8", newline="") as f:
    r = csv.DictReader(f)
    for row in r:
        print(row["nama"], row["nilai"])

Gunakan newline="" saat bekerja dengan CSV untuk mencegah baris kosong ganda di Windows.

9.2 JSON: json.load/json.dump
import json
from pathlib import Path

data = {"versi": 1, "items": [{"id": 1, "nama": "A"}]}
Path("data.json").write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")

with Path("data.json").open("r", encoding="utf-8") as f:
    obj = json.load(f)  # dict

Hindari pickle untuk pertukaran data antar-sistem (alasan keamanan & portabilitas). pickle hanya untuk objek tepercaya di lingkungan Anda sendiri.

10) Penanganan Error (Exception)

Tangkap kesalahan yang wajar—berikan pesan yang membantu pengguna:

from pathlib import Path

def baca_aman(path: Path) -> str:
    try:
        return path.read_text(encoding="utf-8")
    except FileNotFoundError:
        return f"File tidak ditemukan: {path}"
    except PermissionError:
        return f"Tidak punya izin untuk membaca: {path}"
    except UnicodeDecodeError as e:
        return f"Gagal decode UTF-8: {e}"

Daftar exception umum:

  • FileNotFoundError
  • PermissionError
  • IsADirectoryError / NotADirectoryError
  • UnicodeDecodeError
  • OSError (induk bagi banyak I/O error)

11) Operasi Sistem Berkas Umum

from pathlib import Path
root = Path("arsip")

# buat folder
root.mkdir(parents=True, exist_ok=True)

# daftar isi
for p in root.iterdir():
    print(p.name, "DIR" if p.is_dir() else "FILE")

# hapus file
(target := root / "lama.txt").unlink(missing_ok=True)

# pindah/rename
(Path("laporan.txt")).replace(root / "laporan_2025.txt")

12) Best Practices: Keamanan, Kinerja, Kerapian

  1. Selalu with saat buka file.
  2. Eksplisit encoding="utf-8" untuk file teks.
  3. Jangan membaca seluruh file besar sekaligus—pakai iterasi atau chunk.
  4. Validasi path jika berasal dari input pengguna (hindari path traversal seperti ../../ keluar folder kerja).
  5. Tulis atomik untuk file penting: tulis ke file sementara lalu rename (operasi rename biasanya atomik).

    from pathlib import Path
    import os, tempfile
    
    def atomic_write(target: Path, content: str, encoding="utf-8"):
       tmp_dir = target.parent
       with tempfile.NamedTemporaryFile("w", encoding=encoding, dir=tmp_dir, delete=False) as tmp:
           tmp.write(content)
           tmp_name = tmp.name
       os.replace(tmp_name, target)  # atomik di banyak FS
  6. Gunakan newline= yang benar (kosong untuk CSV, \n untuk kontrol eksplisit).
  7. Logging: gunakan modul logging ketimbang menulis log manual bila proyek makin besar.
  8. Jangan pickle data tak tepercaya (rawan eksekusi kode).
  9. Gunakan pathlib untuk portabilitas dan kode yang bersih.
  10. Buffering: tulis chunk 64 KB–1 MB untuk file biner besar.

13) Ringkasan & Cheat Sheet

Ringkasan cepat

  • Gunakan with open(...): ...
  • Teks → encoding="utf-8"; Biner → 'rb'/'wb' tanpa encoding
  • File besar → iterasi baris atau chunk
  • CSV → csv.DictReader/Writer (+ newline="")
  • JSON → json.load/dump (hindari pickle untuk data publik)
  • Path modern → pathlib.Path
  • Tulis aman → atomic write dengan file sementara + os.replace

Cheat Sheet

# baca seluruh teks
Path("a.txt").read_text(encoding="utf-8")

# tulis teks (overwrite)
Path("a.txt").write_text("halo\n", encoding="utf-8", newline="\n")

# iterasi baris
with open("a.txt","r",encoding="utf-8") as f:
    for line in f:
        ...

# copy biner (chunk)
with open("in.bin","rb") as s, open("out.bin","wb") as d:
    while buf := s.read(65536):
        d.write(buf)

# CSV
with open("x.csv","r",encoding="utf-8",newline="") as f:
    r = csv.DictReader(f)
    for row in r: ...

# JSON
obj = json.loads(Path("x.json").read_text(encoding="utf-8"))
Path("y.json").write_text(json.dumps(obj, ensure_ascii=False, indent=2), encoding="utf-8")

# pathlib util
p = Path("data") / "file.txt"
p.parent.mkdir(parents=True, exist_ok=True)
p.exists(), p.is_file(), p.stat().st_size

Tambah komentar

Previous Post Next Post