Operasi Fail dalam Python
Artikel ini menerangkan operasi fail dalam Python.
Dengan mengambil kira "keselamatan", "kecekapan", dan "kebolehbacaan", panduan ini menerangkan konsep langkah demi langkah, dari asas hingga teknik praktikal.
YouTube Video
Operasi Fail dalam Python
Operasi fail ialah kemahiran asas yang penting, daripada skrip kecil hingga aplikasi berskala besar.
Membuka dan menutup fail
Pertama, mari lihat contoh membaca dan menulis fail teks. Menggunakan penyataan with (context manager) memastikan fail ditutup dengan betul.
Kod berikut membuka fail teks, membaca kandungannya, dan memproses setiap baris satu demi satu.
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())- Menetapkan
encoding="utf-8"secara jelas membantu mengurangkan isu bergantung kepada platform. - Walaupun dengan fail besar,
for line in fadalah cekap memori.
Menulis (menulis ganti dan tambahkan)
Ambil perhatian kepada mod ketika menulis ke fail. w untuk menulis ganti, a untuk menambah. Gunakan juga penyataan with ketika menulis.
Kod berikut menunjukkan contoh asas menulis ganti dan menambah.
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")- Kod ini menulis teks ke
output.txtdan kemudian menambah lagi teks kepada fail yang sama. Mod"w"menulis ganti fail, manakala mod"a"menambah baris baharu ke akhir kandungan sedia ada. - Jika perlu buang buffer, panggil
flush(), tetapi biasanya kandungan dibuang secara automatik apabila konteks tamat. - Jika beberapa proses atau utas berkemungkinan menulis secara serentak, kawalan eksklusif seperti penguncian fail perlu dipertimbangkan.
Membaca dan menulis data binari
Imej dan fail termampat dikendalikan dalam mod binari (rb atau wb). Berbeza dengan mod teks, encoding diabaikan.
Kod berikut membaca fail binari dan menyalinnya ke fail lain dalam mod binari.
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)- Apabila mengendalikan fail binari besar, elakkan membaca semuanya sekali gus menggunakan
read(); membaca dan menulis secara pecahan adalah lebih cekap memori.
Contoh mengendalikan fail besar secara pecahan
Untuk fail sangat besar yang tidak muat dalam memori, baca dan tulis secara pecahan saiz tetap. Kerana ianya terhad I/O, melaras saiz penimbal (buffer) adalah berguna.
Kod berikut menyalin fail secara pecahan 64KB. Ini beroperasi dengan pantas sambil mengekalkan penggunaan memori yang 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 boleh melaras saiz pecahan mengikut ciri rangkaian atau cakera anda. Pada SSD, saiz pecahan yang sedikit lebih besar selalunya lebih baik.
Contoh menggunakan argumen buffering
Dengan menentukan argumen buffering dalam fungsi open(), anda boleh mengawal saiz penimbal yang digunakan secara dalaman oleh Python. Ini membolehkan anda mengoptimumkan lagi kecekapan input/output.
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 menetapkan nilai
bufferingkepada 0, I/O akan dilakukan tanpa penimbal; 1 membolehkan penimbal baris, manakala nilai 2 atau lebih menggunakan penimbal dengan saiz khusus dalam bait. - Secara amnya, nilai lalai adalah mencukupi kerana OS mengendalikan cache dengan cekap, tetapi melaraskan parameter ini boleh menjadi berkesan untuk fail yang sangat besar atau peranti khas.
Operasi fail moden menggunakan Pathlib
Modul standard pathlib menjadikan pengendalian laluan lebih intuitif. Ia meningkatkan kebolehbacaan dan keselamatan berbanding penggunaan laluan rentetan.
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)- Kod ini menunjukkan cara membuat direktori dengan
pathlib, menulis ke fail teks, dan membaca kandungannya. Dengan objekPath, anda boleh mengendalikan laluan dengan intuitif dan selamat. Pathmempunyai API yang mudah sepertiiterdir()danglob(). Anda boleh menulis kod tanpa risau tentang pemisah laluan di antara sistem operasi yang berbeza.
Fail dan direktori sementara (tempfile)
Fail sementara boleh dicipta dengan selamat menggunakan tempfile. Ini mengelakkan keadaan persaingan keselamatan dan perlanggaran nama.
Kod berikut menunjukkan contoh membuat data sementara menggunakan fail 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- Kod ini mencipta fail sementara, menulis dan membaca data, dan memadamkannya secara automatik apabila blok
withtamat. Dengantempfile.NamedTemporaryFile, anda boleh mengendalikan fail sementara dengan selamat dan tanpa konflik. Keranadelete=Trueditetapkan, fail akan dipadamkan secara automatik. - Di Windows, anda mungkin tidak dapat membuka fail dari pemegang lain serta-merta, jadi anda boleh tetapkan
delete=Falsedan urus penghapusan secara manual.
shutil: Operasi tahap tinggi untuk menyalin, memindah, dan memadam
Penyalinan, pemindahan, dan pemadaman fail dan direktori secara rekursif adalah 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 masa pengubahsuaian).moveakan cuba memindahkan fail walaupun menukar nama tidak boleh digunakan.rmtreeialah operasi berbahaya, jadi sentiasa sahkan dan buat salinan sandaran sebelum memadam.
Metadata fail (os.stat) dan pengendalian kebenaran
Saiz fail, masa pengubahsuaian, dan kebenaran boleh dibaca dan diubah suai menggunakan os dan stat.
Kod berikut mendapatkan maklumat asas fail dengan os.stat dan menukar kebenaran 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)- Kebenaran berfungsi berbeza pada sistem POSIX dan Windows. Jika keserasian silang platform penting, gunakan API tahap tinggi atau tambah pengendalian bersyarat.
Penguncian fail (kawalan eksklusif) — Perbezaan antara Unix dan Windows
Kawalan eksklusif diperlukan apabila beberapa proses mengakses fail yang sama secara selari. UNIX menggunakan fcntl, dan Windows menggunakan msvcrt.
Kod berikut menggunakan fcntl.flock pada sistem UNIX untuk mendapatkan kunci eksklusif semasa 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)- Kod ini mendapatkan kunci eksklusif menggunakan
fcntl.flockpada sistem seperti UNIX untuk menulis dengan selamat dan mengelakkan penulisan serentak ke fail. Sentiasa lepaskan kunci selepas pemprosesan untuk membolehkan akses oleh proses lain. - Di Windows, gunakan
msvcrt.locking(). Untuk penggunaan tahap lebih tinggi, pertimbangkan pustaka luaran sepertiportalockerataufilelock.
Corak penulisan fail secara atomik
Untuk mengelakkan kerosakan fail semasa kemas kini, tulis ke fail sementara dan gantikan dengan os.replace jika berjaya.
Menulis ke fail sementara dan kemudian menggantikannya dapat mengelakkan kerosakan jika berlaku ranap.
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 atomik dalam sistem fail yang sama. Perhatian bahawa keteratomikan tidak dijamin antara mount yang berbeza.
Akses pantas menggunakan mmap (untuk data berskala besar)
Untuk akses rawak ke fail besar, mmap meningkatkan prestasi I/O. Ia melibatkan operasi binari terutamanya.
Kod berikut memetakan fail ke memori dan membaca atau menulis julat bait tertentu. Berhati-hati apabila menukar saiz fail.
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()- Kod ini memetakan fail binari ke memori menggunakan
mmapdan melakukan operasi baca/tulis terus pada peringkat bait. Pemetaan memori membolehkan akses rawak pantas ke set data besar. mmapsangat cekap, tetapi penggunaan yang salah boleh menyebabkan isu konsistensi data. Panggilflush()untuk membuat penyegerakan jika perlu.
CSV / JSON / Pickle: Membaca dan menulis mengikut format
Format data tertentu mempunyai modul khusus. Gunakan csv untuk CSV, json untuk JSON, dan pickle untuk menyimpan objek Python.
Kod berikut adalah contoh asas membaca dan menulis CSV dan JSON, serta menggunakan Pickle. Kerana Pickle boleh melaksanakan kod sembarangan, elakkan memuatkan data daripada sumber tidak dipercayai.
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)- Menetapkan
newline=""untuk CSV digalakkan untuk mengelakkan baris kosong tambahan di Windows. Denganensure_ascii=False, JSON mengekalkan aksara UTF-8 yang mudah dibaca.
Membaca dan menulis terus fail termampat (gzip / bz2 / zipfile)
Mengendalikan gzip dan zip secara terus boleh menjimatkan ruang cakera. Pustaka standard mengandungi modul yang berkaitan.
Kod berikut ialah contoh mudah membaca dan menulis fail 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())- Terdapat kompromi antara nisbah pemampatan dan kelajuan bergantung pada tahap dan format pemampatan.
Langkah-langkah keselamatan dan kerentanan
Perkara-perkara berikut boleh dipertimbangkan untuk langkah-langkah keselamatan dan kerentanan.
- Jangan guna input tidak dipercayai secara langsung dalam nama fail atau laluan.
- Gunakan Pickle hanya dengan sumber dipercayai.
- Minimumkan keistimewaan pelaksanaan, dan beri hanya kebenaran minimum kepada proses yang mengendalikan fail.
- Guna fail sementara dengan
tempfile, dan jangan simpan fail biasa dalam direktori umum.
Jika menggunakan input pengguna dalam laluan fail, normalisasi dan pengesahan diperlukan. Contohnya, 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')- Berhati-hati khasnya apabila menggunakan input luar sebagai laluan fail dalam aplikasi web atau API awam.
Ringkasan corak umum
- Sentiasa gunakan penyataan
with(penutupan automatik). - Nyatakan
encodingsecara jelas untuk data teks. - Baca dan tulis fail besar secara pecahan.
- Perkenalkan penguncian fail untuk sumber yang dikongsi.
- Untuk kemas kini penting, gunakan corak atomik iaitu 'tulis ke fail sementara → os.replace'.
- Sentiasa sahkan dan buat sandaran sebelum melakukan operasi berbahaya (seperti penghapusan atau penimpaan).
- Normalkan dan sahkan apabila menggunakan input luaran sebagai laluan fail.
Ringkasan
Untuk operasi fail, adalah penting menggunakan teknik yang selamat dan boleh dipercayai seperti menggunakan pernyataan with, menetapkan pengekodan secara khusus, dan penulisan atomik. Untuk pemprosesan berskala besar atau akses selari, adalah perlu melaksanakan sistem penguncian dan pengurusan log untuk mencegah kerosakan dan konflik data. Mengimbangi kecekapan dan keselamatan adalah kunci kepada operasi fail yang boleh dipercayai.
Anda boleh mengikuti artikel di atas menggunakan Visual Studio Code di saluran YouTube kami. Sila lihat juga saluran YouTube kami.