Operasyon ng File sa Python

Operasyon ng File sa Python

Ipinaliliwanag ng artikulong ito ang mga operasyon ng file sa Python.

Sa isip ang "kaligtasan," "kahusayan," at "kababasa," ipinaliwanag ng gabay na ito ang mga konsepto hakbang-hakbang, mula sa mga batayan hanggang sa mga praktikal na teknik.

YouTube Video

Operasyon ng File sa Python

Ang mga operasyon ng file ay isang mahalagang pangunahing kasanayan, mula sa maliliit na script hanggang sa malakihang mga aplikasyon.

Pagbubukas at pagsasara ng mga file

Una, tingnan natin ang mga halimbawa ng pagbabasa at pagsusulat ng mga text file. Sa paggamit ng with na pahayag (context manager), natitiyak na maayos na isasara ang file.

Binubuksan ng sumusunod na code ang isang text file, binabasa ang nilalaman nito, at pinoproseso ito kada linya.

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())
  • Ang hayagang paglalagay ng encoding="utf-8" ay tumutulong mabawasan ang mga isyung nakadepende sa platform.
  • Kahit sa malalaking file, memory efficient ang paggamit ng for line in f.

Pagsusulat (pag-overwrite at pag-append)

Pansinin ang mode kapag nagsusulat sa mga file. Ang w ay para sa pag-­overwrite, ang a ay para sa pag-append. Gamitin din ang with na pahayag kapag sumusulat.

Ipinapakita ng sumusunod na code ang mga pangunahing halimbawa ng pag-overwrite at pag-append.

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")
  • Sumusulat ang code na ito ng text sa output.txt at nagdadagdag pa ng karagdagang teksto sa parehong file. Ang mode na "w" ay nag-o-overwrite ng file, habang ang "a" mode ay nagdadagdag ng bagong linya sa dulo ng kasalukuyang nilalaman.
  • Kung kinakailangan mong i-flush, tawagin ang flush(), pero karaniwang awtomatikong nai-flush ang nilalaman kapag natapos ang context.
  • Kung maraming proseso o thread ang sabay-sabay na maaaring magsulat, kailangan mong isaalang-alang ang exclusive control gaya ng file locking.

Pagbasa at pagsusulat ng binary data

Ang mga larawan at compressed na file ay pinoproseso sa binary mode (rb o wb). Hindi tulad ng text mode, hindi pinapansin ang encoding.

Binabasa ng sumusunod na code ang isang binary file at kinokopya ito sa ibang file gamit ang binary mode.

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)
  • Kapag humahawak ng malalaking binary file, iwasang basahin ang lahat sabay-sabay gamit ang read(); mas memory efficient ang pagbasa at pagsusulat sa bahagi-bahagi (chunks).

Halimbawa ng paghawak ng malalaking file sa pamamagitan ng chunks

Para sa napakalalaking file na hindi kasya sa memorya, basahin at isulat ang mga ito sa mga chunk na may tiyak na laki. Dahil ito ay I/O-bound, kapaki-pakinabang ang pag-aayos ng laki ng buffer.

Kinokopya ng sumusunod na code ang isang file sa 64KB chunks. Mabilis itong gumagana habang mababa ang paggamit ng memorya.

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)
  • Maaari mong ayusin ang laki ng chunk ayon sa katangian ng iyong network o disk. Sa SSDs, kadalasang mas mainam ang bahagyang mas malaking chunk size.

Halimbawa ng paggamit ng buffering na argumento

Sa pamamagitan ng pagtukoy ng buffering na argumento sa open() na function, maaari mong kontrolin ang laki ng buffer na ginagamit sa loob ng Python. Pinapahintulutan ka nitong higit pang ma-optimize ang kahusayan ng 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)
  • Kung itatakda mo ang halaga ng buffering sa 0, isinasagawa ang I/O nang walang buffering; 1 ay nagbibigay-daan sa line buffering, habang ang mga halagang 2 o mas mataas ay gumagamit ng buffer ayon sa tinukoy na laki sa bytes.
  • Sa pangkalahatan, sapat na ang default na halaga dahil mahusay na hinahawakan ng OS ang caching, ngunit ang pag-aayos ng parameter na ito ay maaaring maging epektibo para sa napakalalaking file o espesyal na mga device.

Makabago at modernong operasyon ng file gamit ang Pathlib

Ginagawang mas intuitive ang paghawak ng mga path ng standard na pathlib module. Pinapabuti nito ang kababasa at kaligtasan kumpara sa paggamit ng string paths.

 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)
  • Ipinapakita ng code na ito ang paggawa ng directory gamit ang pathlib, pagsusulat ng text file, at pagbabasa ng nilalaman nito. Gamit ang Path object, maaari mong hawakan ang mga path sa paraang intuitive at ligtas.
  • May mga maginhawang API ang Path tulad ng iterdir() at glob(). Maaari kang magsulat ng code nang hindi iniisip ang tungkol sa path separator sa iba't ibang operating system.

Pansamantalang file at direktoryo (tempfile)

Ligtas kang makakalikha ng pansamantalang file gamit ang tempfile. Ipinaiiwas nito ang security race conditions at banggaan ng pangalan (name collisions).

Ipinapakita ng sumusunod na code ang halimbawa ng paggawa ng pansamantalang data gamit ang pansamantalang file.

 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
  • Gumagawa ang code na ito ng pansamantalang file, nagsusulat at nagbabasa ng data, at awtomatikong nagbubura kapag natapos ang with block. Sa paggamit ng tempfile.NamedTemporaryFile, makakapag-handle ka ng temporary files nang ligtas at walang conflict. Dahil naka-set ang delete=True, awtomatikong nabubura ang file.
  • Sa Windows, maaaring hindi mo agad mabuksan ang file mula sa ibang handle, kaya puwede mong itakda ang delete=False at ikaw na ang magbura nito.

shutil: Mataas na antas ng mga operasyon para sa pagkopya, paglipat, at pagbura

Madaling gawin ang recursive na pagkopya, paglipat, at pagbura ng mga file at direktoryo gamit ang 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")
  • Kinokopya rin ng shutil.copy2 ang metadata (tulad ng oras ng pagbabago). Ang move ay magmo-move pa rin ng file kahit hindi magamit ang rename.
  • Ang rmtree ay mapanganib na operasyon, kaya laging kumpirmahin at mag-backup bago magbura.

File metadata (os.stat) at paghawak ng permiso

Ang laki ng file, oras ng pagbabago, at permiso ay maaaring basahin at ayusin gamit ang os at stat.

Kinukuha ng sumusunod na code ang pangunahing impormasyon ng file gamit ang os.stat at binabago ang permiso gamit ang 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)
  • Iba ang paggalaw ng mga permiso sa POSIX at Windows na sistema. Kung mahalaga ang cross-platform na compatibility, gumamit ng high-level na API o dagdagan ng conditional na paghawak.

File locking (exclusive control) — Pagkakaiba ng Unix at Windows

Kinakailangan ang exclusive control kapag maraming proseso ang sabay-sabay na nag-a-access ng parehong file. Gumagamit ang UNIX ng fcntl, at gumagamit ang Windows ng msvcrt.

Gumagamit ang sumusunod na code ng fcntl.flock sa UNIX system para maglagay ng exclusive lock habang sumusulat.

 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)
  • Nakakakuha ang code na ito ng exclusive lock gamit ang fcntl.flock sa UNIX-like na system para ligtas na magsulat at pigilan ang sabay-sabay na pagsusulat sa file. Palaging pakawalan ang lock pagkatapos ng proseso para makapag-access ang ibang proseso.
  • Sa Windows, gamitin ang msvcrt.locking(). Para sa mas mataas na antas na paggamit, isaalang-alang ang external na library tulad ng portalocker o filelock.

Mga atomic na pattern sa pagsusulat ng file

Upang maiwasan ang pagkasira ng file habang ina-update, magsulat muna sa pansamantalang file at palitan gamit ang os.replace kapag matagumpay.

Ang pagsusulat muna sa pansamantalang file at pagpapalit nito ay umiiwas sa pagkasira kung magka-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')

Ang os.replace ay gumagawa ng atomic na pagpapalit sa loob ng iisang file system. Tandaan na hindi garantisado ang atomicity kapag iba't ibang mount ang ginagamit.

Mabilis na access gamit ang mmap (para sa malalaking datos)

Para sa random na pag-access ng malalaking file, pinapabuti ng mmap ang I/O performance. Kadalasan ay may kinalaman ito sa binary operations.

Memory-maps ng sumusunod na code ang isang file at nagbabasa o nagsusulat ng mga tiyak na byte range. Maging maingat kapag binabago ang laki ng 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()
  • Imi-mamapa ng code na ito ang isang binary file sa memorya gamit ang mmap at gumagawa ng direktang byte-level na pagbabasa/pagsusulat. Ang memory mapping ay nagbibigay-daan sa mabilis na random access sa malalaking dataset.
  • Mabisa ang mmap, ngunit ang maling paggamit ay maaaring humantong sa isyu ng consistency ng data. Tawagin ang flush() para mag-synchronize ayon sa pangangailangan.

CSV / JSON / Pickle: Pagbabasa at pagsusulat ayon sa format

May nakalaang module para sa bawat partikular na uri ng data format. Gamitin ang csv para sa CSV, json para sa JSON, at pickle para sa pag-save ng Python objects.

Nagbibigay ang sumusunod na code ng pangunahing halimbawa ng pagbabasa at pagsusulat ng CSV at JSON, at paggamit ng Pickle. Dahil maaaring magpatakbo ng arbitrary code ang Pickle, iwasang mag-load ng data mula sa hindi mapagkakatiwalaang source.

 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)
  • Iminumungkahi ang pagtatakda ng newline="" para sa CSV upang maiwasan ang sobrang blank line sa Windows. Sa ensure_ascii=False, nananatiling nababasa ang mga UTF-8 character sa JSON.

Direktang pagbabasa at pagsusulat ng compressed file (gzip / bz2 / zipfile)

Ang direktang paghawak ng gzip at zip ay makakatipid ng disk space. Kasama sa standard library ang mga kaukulang module.

Ang sumusunod na code ay simpleng halimbawa ng pagbabasa at pagsusulat ng gzip files bilang text.

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())
  • May pag-papalit sa pagitan ng compression ratio at bilis depende sa antas ng compression at format.

Mga hakbang para sa seguridad at kahinaan

Ang mga sumusunod na punto ay maaaring isaalang-alang para sa mga hakbang sa seguridad at kahinaan.

  • Huwag gumamit ng hindi mapagkakatiwalaang input direkta sa file name o path.
  • Gamitin lamang ang Pickle sa mapagkakatiwalaang source.
  • Bawasan ang execution privileges, at ibigay lamang ang minimum na permiso sa mga prosesong humahawak ng file.
  • Gamitin ang temporary files gamit ang tempfile, at huwag mag-imbak ng mga plain filse sa public directory.

Kung gagamit ng user input sa file path, kailangan ang normalization at validation. Halimbawa, gamitin ang Path.resolve() at i-check ang parent directory.

 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')
  • Maging extra-ingat kapag gumagamit ng external input bilang file path sa web app o public API.

Buod ng karaniwang mga pattern

  • Laging gamitin ang with na pahayag (awtomatikong pagsasara ng file).
  • Hayagang itakda ang encoding para sa text data.
  • Basahin at isulat ang malalaking file ng pa-chunk/chunked.
  • Magpakilala ng file locking para sa mga pinaghahatian na mapagkukunan.
  • Para sa mahahalagang update, gamitin ang atomic pattern na 'isulat muna sa temporary file → os.replace'.
  • Palaging kumpirmahin at lumikha ng backup bago magsagawa ng mga mapanganib na operasyon (tulad ng pagtanggal o pag-overwrite).
  • I-normalize at i-validate kapag gumagamit ng external na input bilang path ng file.

Buod

Para sa mga operasyon ng file, mahalaga ang paggamit ng ligtas at maaasahang mga paraan tulad ng paggamit ng with statement, tahasang pagtatakda ng encoding, at atomic na pagsusulat. Para sa malakihang pagproseso o sabayang pag-access, kinakailangang magpatupad ng locking at log management system upang maiwasan ang suhayan at banggaan ng data. Ang balanseng kahusayan at kaligtasan ay susi sa maaasahang operasyon ng file.

Maaari mong sundan ang artikulo sa itaas gamit ang Visual Studio Code sa aming YouTube channel. Paki-check din ang aming YouTube channel.

YouTube Video