Operasi File di Python
Artikel ini menjelaskan operasi file di Python.
Dengan mempertimbangkan "keamanan", "efisiensi", dan "keterbacaan", panduan ini menjelaskan konsep langkah demi langkah, dari dasar hingga teknik praktis.
YouTube Video
Operasi File di Python
Operasi file adalah keterampilan dasar yang penting, mulai dari skrip kecil hingga aplikasi skala besar.
Membuka dan menutup file
Pertama, mari kita lihat contoh membaca dan menulis file teks. Menggunakan pernyataan with (context manager) memastikan file ditutup dengan benar.
Kode berikut membuka file teks, membaca isinya, dan memprosesnya baris demi baris.
1# Open and read a text file safely using a context manager.
2with open("example.txt", "r", encoding="utf-8") as f:
3 # Read all lines lazily (as an iterator) and process each line.
4 for line in f:
5 print(line.rstrip())- Secara eksplisit menentukan
encoding="utf-8"membantu mengurangi masalah tergantung platform. - Bahkan untuk file besar,
for line in ftetap efisien dalam penggunaan memori.
Menulis (menimpa dan menambahkan)
Perhatikan mode saat menulis ke file. w untuk menimpa, a untuk menambahkan. Gunakan pernyataan with juga saat menulis.
Kode berikut menunjukkan contoh dasar menimpa dan menambahkan.
1# Write (overwrite) to a file.
2with open("output.txt", "w", encoding="utf-8") as f:
3 f.write("First line\n")
4 f.write("Second line\n")
5
6# Append to the same file.
7with open("output.txt", "a", encoding="utf-8") as f:
8 f.write("Appended line\n")- Kode ini menulis teks ke
output.txtlalu menambahkan teks lagi ke file yang sama. Mode"w"menimpa file, sedangkan mode"a"menambahkan baris baru di akhir konten yang ada. - Jika perlu melakukan flush, panggil
flush(), tetapi biasanya isi file akan ter-flush otomatis saat konteks berakhir. - Jika beberapa proses atau thread dapat menulis secara bersamaan, Anda perlu mempertimbangkan kontrol eksklusif seperti file locking.
Membaca dan menulis data biner
Gambar dan file terkompresi diproses dalam mode biner (rb atau wb). Berbeda dengan mode teks, encoding diabaikan.
Kode berikut membaca file biner dan menyalinnya ke file lain dalam mode biner.
1# Read and write binary files.
2with open("image.png", "rb") as src:
3 data = src.read()
4
5with open("copy.png", "wb") as dst:
6 dst.write(data)- Saat menangani file biner besar, hindari membaca semuanya sekaligus dengan
read(); membaca dan menulis secara bertahap (chunk) lebih efisien memori.
Contoh penanganan file besar secara bertahap (chunk)
Untuk file sangat besar yang tidak muat di memori, baca dan tulislah dalam potongan berukuran tetap. Karena ini terkait I/O, mengatur ukuran buffer akan berguna.
Kode berikut menyalin file dalam potongan 64KB. Ini bekerja dengan cepat sambil menjaga penggunaan memori tetap rendah.
1# Copy a large file in chunks to avoid using too much memory.
2CHUNK_SIZE = 64 * 1024 # 64 KB
3
4with open("large_source.bin", "rb") as src, open("large_dest.bin", "wb") as dst:
5 while True:
6 chunk = src.read(CHUNK_SIZE)
7 if not chunk:
8 break
9 dst.write(chunk)- Anda dapat menyesuaikan ukuran chunk sesuai karakteristik jaringan atau diska Anda. Pada SSD, ukuran chunk yang sedikit lebih besar sering kali bekerja lebih baik.
Contoh penggunaan argumen buffering
Dengan menentukan argumen buffering dalam fungsi open(), Anda dapat mengontrol ukuran buffer yang digunakan secara internal oleh Python. Ini memungkinkan Anda untuk mengoptimalkan efisiensi input/output lebih lanjut.
1# Explicitly set the internal buffer size to 128 KB for faster I/O.
2CHUNK_SIZE = 64 * 1024
3BUFFER_SIZE = 128 * 1024 # 128 KB internal buffer
4
5with open("large_source.bin", "rb", buffering=BUFFER_SIZE) as src, open("large_dest.bin", "wb", buffering=BUFFER_SIZE) as dst:
6 while True:
7 chunk = src.read(CHUNK_SIZE)
8 if not chunk:
9 break
10 dst.write(chunk)- Jika Anda mengatur nilai
bufferingke 0, I/O dilakukan tanpa buffering; 1 mengaktifkan buffering per baris, sedangkan nilai 2 atau lebih akan menggunakan buffer dengan ukuran yang ditentukan dalam byte. - Secara umum, nilai default sudah cukup karena OS menangani caching dengan efisien, namun menyesuaikan parameter ini bisa efektif untuk file yang sangat besar atau perangkat khusus.
Operasi file modern menggunakan Pathlib
Modul standar pathlib membuat penanganan path menjadi lebih intuitif. Ini meningkatkan keterbacaan dan keamanan dibandingkan dengan path berbasis string.
1from pathlib import Path
2
3path = Path("data") / "notes.txt"
4
5# Ensure parent directory exists.
6path.parent.mkdir(parents=True, exist_ok=True)
7
8# Write and read using pathlib.
9path.write_text("Example content\n", encoding="utf-8")
10content = path.read_text(encoding="utf-8")
11print(content)- Kode ini mendemonstrasikan membuat direktori dengan
pathlib, menulis ke file teks, dan membaca isinya. Dengan objekPath, Anda dapat menangani path secara intuitif dan aman. Pathmemiliki API yang praktis sepertiiterdir()danglob(). Anda bisa menulis kode tanpa khawatir tentang pemisah path antar sistem operasi.
File dan direktori sementara (tempfile)
File sementara dapat dibuat dengan aman menggunakan tempfile. Ini mencegah race condition keamanan dan tabrakan nama.
Kode berikut menunjukkan contoh membuat data sementara menggunakan file sementara.
1import tempfile
2
3# Create a temporary file that is deleted on close.
4with tempfile.NamedTemporaryFile(
5 mode="w+",
6 encoding="utf-8",
7 delete=True
8) as tmp:
9 tmp.write("temporary data\n")
10 tmp.seek(0)
11 print(tmp.read())
12
13# tmp is deleted here- Kode ini membuat file sementara, menulis dan membaca data, lalu menghapusnya secara otomatis saat blok
withberakhir. Dengantempfile.NamedTemporaryFile, Anda dapat menangani file sementara secara aman dan tanpa konflik. Karenadelete=Trueditentukan, file akan dihapus secara otomatis. - Di Windows, Anda mungkin tidak bisa membuka file dari handle lain secara langsung, jadi Anda bisa menetapkan
delete=Falsedan mengelola penghapusan sendiri.
shutil: Operasi tingkat tinggi untuk menyalin, memindah, dan menghapus
Penyalinan, pemindahan, serta penghapusan file dan direktori secara rekursif menjadi mudah dengan shutil.
1import shutil
2
3# Copy a file preserving metadata.
4shutil.copy2("source.txt", "dest.txt")
5
6# Move a file or directory.
7shutil.move("old_location", "new_location")
8
9# Remove an entire directory tree (use with caution).
10shutil.rmtree("some_directory")shutil.copy2juga menyalin metadata (seperti waktu modifikasi).moveakan tetap memindahkan file walaupun rename tidak bisa digunakan.rmtreeadalah operasi berbahaya, jadi selalu konfirmasi dan backup sebelum menghapus.
Metadata file (os.stat) dan penanganan izin
Ukuran file, waktu modifikasi, dan izin dapat dibaca dan diubah menggunakan os dan stat.
Kode berikut memperoleh informasi dasar file dengan os.stat dan mengubah izin dengan os.chmod.
1import os
2import stat
3from datetime import datetime
4
5st = os.stat("example.txt")
6print("size:", st.st_size)
7print("modified:", datetime.fromtimestamp(st.st_mtime))
8
9# Make file read-only for owner.
10os.chmod("example.txt", stat.S_IREAD)- Izin berperilaku berbeda di sistem POSIX dan Windows. Jika kompatibilitas lintas platform penting, gunakan API tingkat tinggi atau tambahkan penanganan bersyarat.
Penguncian file (kontrol eksklusif) — Perbedaan antara Unix dan Windows
Kontrol eksklusif diperlukan saat beberapa proses mengakses file yang sama secara paralel. UNIX menggunakan fcntl, dan Windows menggunakan msvcrt.
Kode berikut menggunakan fcntl.flock pada sistem UNIX untuk memperoleh kunci eksklusif saat menulis.
1# Unix-style file locking example
2import fcntl
3
4with open("output.txt", "a+", encoding="utf-8") as f:
5 fcntl.flock(f, fcntl.LOCK_EX)
6 try:
7 f.write("Safe write\n")
8 f.flush()
9 finally:
10 fcntl.flock(f, fcntl.LOCK_UN)- Kode ini memperoleh kunci eksklusif menggunakan
fcntl.flockpada sistem mirip UNIX untuk menulis dengan aman dan mencegah penulisan bersamaan ke file. Selalu lepaskan kunci setelah pemrosesan agar proses lain bisa mengakses. - Di Windows, gunakan
msvcrt.locking(). Untuk penggunaan tingkat lebih tinggi, pertimbangkan pustaka eksternal sepertiportalockerataufilelock.
Pola penulisan file atomik
Untuk mencegah kerusakan file saat pembaruan, tulis ke file sementara lalu ganti menggunakan os.replace jika berhasil.
Menulis ke file sementara lalu menggantinya mencegah kerusakan file jika terjadi crash.
1import os
2from pathlib import Path
3import tempfile
4
5def atomic_write(path: Path, data: str, encoding="utf-8"):
6 # Write to a temp file in the same directory and atomically replace.
7 dirpath = path.parent
8 with tempfile.NamedTemporaryFile(
9 mode="w",
10 encoding=encoding,
11 dir=str(dirpath),
12 delete=False
13 ) as tmp:
14 tmp.write(data)
15 tmp.flush()
16 tempname = tmp.name
17
18 # Atomic replacement (on most OSes)
19 os.replace(tempname, str(path))
20
21# Usage
22atomic_write(Path("config.json"), '{"key":"value"}\n')os.replace melakukan penggantian secara atomik dalam sistem file yang sama. Harap dicatat bahwa atomisitas tidak dijamin antar mount yang berbeda.
Akses cepat menggunakan mmap (untuk data skala besar)
Untuk akses acak ke file besar, mmap meningkatkan performa I/O. Ini terutama melibatkan operasi biner.
Kode berikut melakukan memory-mapping pada file dan membaca atau menulis rentang byte tertentu. Berhati-hatilah saat mengubah ukuran file.
1import mmap
2
3with open("data.bin", "r+b") as f:
4 mm = mmap.mmap(f.fileno(), 0) # map entire file
5 try:
6 print(mm[:20]) # first 20 bytes
7 mm[0:4] = b"\x00\x01\x02\x03" # modify bytes
8 finally:
9 mm.close()- Kode ini memetakan file biner ke memori dengan
mmapdan melakukan operasi membaca/menulis tingkat byte secara langsung. Memory mapping memungkinkan akses acak yang cepat ke dataset besar. mmapefisien, tetapi penggunaan yang salah dapat menyebabkan masalah konsistensi data. Panggilflush()untuk sinkronisasi jika diperlukan.
CSV / JSON / Pickle: Membaca dan menulis berdasarkan format
Format data tertentu memiliki modul khusus. Gunakan csv untuk CSV, json untuk JSON, dan pickle untuk menyimpan objek Python.
Kode berikut memberikan contoh dasar membaca dan menulis CSV dan JSON, serta menggunakan Pickle. Karena Pickle dapat mengeksekusi kode sembarangan, hindari memuat data dari sumber tidak tepercaya.
1import csv
2import json
3import pickle
4
5# CSV write
6with open("rows.csv", "w", encoding="utf-8", newline="") as f:
7 writer = csv.writer(f)
8 writer.writerow(["name", "age"])
9 writer.writerow(["Alice", 30])
10
11# JSON write
12data = {"items": [1, 2, 3]}
13with open("data.json", "w", encoding="utf-8") as f:
14 json.dump(data, f, ensure_ascii=False, indent=2)
15
16# Pickle write (only for trusted environments)
17obj = {"key": "value"}
18with open("obj.pkl", "wb") as f:
19 pickle.dump(obj, f)- Menentukan
newline=""untuk CSV direkomendasikan agar baris kosong tambahan tidak muncul di Windows. Denganensure_ascii=False, JSON membuat karakter UTF-8 tetap terbaca.
Membaca dan menulis file terkompresi secara langsung (gzip / bz2 / zipfile)
Menangani gzip dan zip secara langsung dapat menghemat ruang diska. Pustaka standar sudah menyertakan modul yang sesuai.
Kode berikut adalah contoh sederhana membaca dan menulis file gzip sebagai teks.
1import gzip
2
3# Write gzipped text.
4with gzip.open("text.gz", "wt", encoding="utf-8") as f:
5 f.write("Compressed content\n")
6
7# Read gzipped text.
8with gzip.open("text.gz", "rt", encoding="utf-8") as f:
9 print(f.read())- Ada kompromi antara rasio kompresi dan kecepatan tergantung pada tingkat dan format kompresi.
Langkah-langkah keamanan dan kerentanan
Poin-poin berikut dapat dipertimbangkan untuk langkah-langkah keamanan dan kerentanan.
- Jangan gunakan input tak tepercaya secara langsung dalam nama atau path file.
- Gunakan Pickle hanya untuk sumber yang tepercaya.
- Minimalkan hak eksekusi, dan berikan hanya izin minimum ke proses yang menangani file.
- Gunakan file sementara dengan
tempfile, dan jangan menyimpan file biasa di direktori publik.
Jika menggunakan input pengguna dalam path file, diperlukan normalisasi dan validasi. Misalnya, gunakan Path.resolve() dan periksa direktori induk.
1from pathlib import Path
2
3def safe_path(base_dir: Path, user_path: str) -> Path:
4 candidate = (base_dir / user_path).resolve()
5 if base_dir.resolve() not in candidate.parents and base_dir.resolve() != candidate:
6 raise ValueError("Invalid path")
7 return candidate
8
9# Usage
10base = Path("/srv/app/data")
11
12# Raises an exception: attempted path traversal outside `base`
13safe = safe_path(base, '../etc/passwd')- Sangat berhati-hatilah saat menggunakan input eksternal sebagai path file pada aplikasi web atau API publik.
Ringkasan pola umum
- Selalu gunakan pernyataan
with(penutupan otomatis). - Tentukan
encodingsecara eksplisit untuk data teks. - Baca dan tulis file besar secara bertahap (chunk).
- Terapkan penguncian file untuk sumber daya bersama.
- Untuk pembaruan penting, gunakan pola atomik 'tulis ke file sementara → os.replace'.
- Selalu konfirmasi dan buat cadangan sebelum melakukan operasi berbahaya (seperti penghapusan atau penimpaan).
- Normalisasi dan validasi ketika menggunakan input eksternal sebagai jalur file.
Ringkasan
Untuk operasi file, penting untuk menggunakan teknik yang aman dan andal seperti menggunakan pernyataan with, menentukan encoding secara eksplisit, dan penulisan secara atomik. Untuk pemrosesan skala besar atau akses paralel, perlu menerapkan sistem penguncian dan manajemen log untuk mencegah kerusakan dan konflik data. Menyeimbangkan efisiensi dan keamanan adalah kunci untuk operasi file yang andal.
Anda dapat mengikuti artikel di atas menggunakan Visual Studio Code di saluran YouTube kami. Silakan periksa juga saluran YouTube kami.