Filoperationer i Python
Denne artikel forklarer filoperationer i Python.
Med fokus på "sikkerhed", "effektivitet" og "læsbarhed" forklarer denne guide koncepterne trin-for-trin, fra det grundlæggende til praktiske teknikker.
YouTube Video
Filoperationer i Python
Filoperationer er en essentiel og grundlæggende færdighed, fra små scripts til store applikationer.
Åbning og lukning af filer
Lad os først se på eksempler på læsning og skrivning af tekstfiler. Brug af with-sætningen (kontekst-manager) sikrer, at filen lukkes korrekt.
Koden nedenfor åbner en tekstfil, læser indholdet og behandler det linje for linje.
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())- Ved eksplicit at angive
encoding="utf-8"reduceres platformafhængige problemer. - Selv med store filer er
for line in fhukommelseseffektivt.
Skrivning (overskriv og tilføj)
Vær opmærksom på tilstanden (mode), når der skrives til filer. w er til overskrivning, a er til tilføjelse. Brug også with-sætningen ved skrivning.
Koden nedenfor viser grundlæggende eksempler på overskrivning og tilføjelse.
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")- Denne kode skriver tekst til
output.txtog tilføjer derefter mere tekst til samme fil."w"-tilstanden overskriver filen, mens"a"-tilstanden tilføjer en ny linje til slutningen af det eksisterende indhold. - Hvis du skal tømme bufferen, kan du kalde
flush(), men normalt tømmes indholdet automatisk, når konteksten slutter. - Hvis flere processer eller tråde kan skrive samtidigt, skal du overveje eksklusiv kontrol såsom fil-låsning.
Læsning og skrivning af binære data
Billeder og komprimerede filer håndteres i binær tilstand (rb eller wb). I modsætning til teksttilstand ignoreres encoding.
Koden nedenfor læser en binær fil og kopierer den til en anden fil i binær tilstand.
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)- Ved håndtering af store binære filer, undgå at læse alt på én gang med
read(); læs og skriv i stykker for bedre hukommelseseffektivitet.
Eksempel på håndtering af store filer i stykker
For meget store filer, der ikke kan være i hukommelsen, læs og skriv i faste størrelsesblokke. Da dette er I/O-begrænset, er det nyttigt at justere buffertens størrelse.
Koden nedenfor kopierer en fil i blokke på 64KB. Dette gør det hurtigt og holder hukommelsesforbruget lavt.
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)- Du kan justere blokstørrelsen efter netværks- eller diskens egenskaber. For SSD'er fungerer en lidt større blokstørrelse ofte bedre.
Eksempel på brug af buffering-argumentet
Ved at angive buffering-argumentet i open()-funktionen kan du styre den bufferstørrelse, som Python bruger internt. Dette giver dig mulighed for yderligere at optimere input/output-effektiviteten.
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)- Hvis du sætter værdien af
bufferingtil 0, udføres I/O uden buffering; 1 aktiverer linjebuffering, mens værdier på 2 eller højere bruger en buffer med den angivne størrelse i bytes. - Generelt er standardværdien tilstrækkelig, fordi operativsystemet håndterer caching effektivt, men justering af denne parameter kan være effektivt for meget store filer eller specielle enheder.
Moderne filoperationer med Pathlib
Det standard pathlib-modul gør stihåndtering mere intuitiv. Det forbedrer læsbarheden og sikkerheden sammenlignet med streng-baserede stier.
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)- Denne kode demonstrerer, hvordan man opretter en mappe med
pathlib, skriver til en tekstfil, og læser indholdet. Med etPath-objekt kan du håndtere stier både intuitivt og sikkert. Pathhar praktiske API'er såsomiterdir()ogglob(). Du kan skrive kode uden at bekymre dig om skillelinjer i stier mellem forskellige operativsystemer.
Midlertidige filer og mapper (tempfile)
Midlertidige filer kan oprettes sikkert med tempfile. Dette undgår sikkerhedsmæssige race-tilstande og navnekonflikter.
Koden nedenfor viser et eksempel på oprettelse af midlertidige data med en midlertidig fil.
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- Denne kode opretter en midlertidig fil, skriver og læser data og sletter den automatisk, når
with-blokken slutter. Ved at brugetempfile.NamedTemporaryFilekan du håndtere midlertidige filer sikkert og uden konflikter. Fordidelete=Trueer angivet, slettes filen automatisk. - På Windows kan filen muligvis ikke åbnes med et andet håndtag med det samme, så du kan sætte
delete=Falseog selv stå for sletningen.
shutil: Højniveau operationer til kopiering, flytning og sletning
Rekursiv kopiering, flytning og sletning af filer og mapper er nemt med 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.copy2kopierer også metadata (såsom ændringstidspunkt).movevil falde tilbage til at flytte filen, selvom omdøbning ikke kan bruges.rmtreeer en farlig handling, så bekræft altid og lav backup før du sletter.
Fil-metadata (os.stat) og håndtering af tilladelser
Filstørrelse, ændringstid og rettigheder kan læses og ændres med os og stat.
Nedenstående kode indhenter grundlæggende filinformation med os.stat og ændrer rettigheder med 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)- Rettigheder opfører sig forskelligt på POSIX- og Windows-systemer. Hvis platformskompatibilitet er vigtigt, skal du bruge ovenliggende API'er eller tilføje betinget logik.
Fillåsning (eksklusiv kontrol) — forskelle mellem Unix og Windows
Eksklusiv kontrol er nødvendig, når flere processer tilgår den samme fil parallelt. UNIX bruger fcntl, og Windows bruger msvcrt.
Nedenstående kode bruger fcntl.flock på UNIX-systemer for at opnå en eksklusiv lås ved skrivning.
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)- Denne kode opnår en eksklusiv lås med
fcntl.flockpå UNIX-lignende systemer for at skrive sikkert og forhindre samtidige skrivninger til filen. Frigiv altid låsen efter behandling for at give andre processer adgang. - På Windows skal du bruge
msvcrt.locking(). For mere avanceret brug, overvej eksterne biblioteker somportalockerellerfilelock.
Atomare filskrivningsmønstre
For at forhindre filkorruption under opdateringer, skriv til en midlertidig fil og erstat den med os.replace, hvis alt lykkes.
Skrivning til en midlertidig fil og derefter udskiftning undgår korruption, hvis der sker et nedbrud.
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 udfører en atomar udskiftning inden for det samme filsystem. Bemærk at atomaritet ikke er garanteret på tværs af forskellige monterede filsystemer.
Hurtig adgang med mmap (til store datamængder)
Til tilfældig adgang til store filer gør mmap I/O hurtigere. Det involverer primært binære operationer.
Nedenstående kode memory-mapper en fil og læser eller skriver bestemte byte-intervaller. Vær forsigtig, når du ændrer filstørrelsen.
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()- Denne kode mapper en binær fil til hukommelsen med
mmapog udfører direkte læse-/skriveoperationer på byteniveau. Memory-mapping muliggør hurtig, tilfældig adgang til store datamængder. mmaper effektivt, men forkert brug kan føre til datakonsistensproblemer. Kaldflush()for at synkronisere efter behov.
CSV / JSON / Pickle: Læsning og skrivning pr. format
Specifikke dataformater har dedikerede moduler. Brug csv til CSV, json til JSON og pickle til at gemme Python-objekter.
Nedenstående kode giver grundlæggende eksempler på læsning og skrivning af CSV, JSON og brug af Pickle. Da Pickle kan eksekvere vilkårlig kode, undgå at indlæse data fra ikke-betroede kilder.
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)- Det anbefales at angive
newline=""for CSV for at undgå ekstra tomme linjer på Windows. Medensure_ascii=Falseforbliver UTF-8-tegn i JSON læsbare.
Direkte læsning og skrivning af komprimerede filer (gzip / bz2 / zipfile)
Direkte håndtering af gzip og zip kan spare diskplads. Standardbiblioteket indeholder tilsvarende moduler.
Nedenstående kode er et simpelt eksempel på læsning og skrivning af gzip-filer som tekst.
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())- Der er en afvejning mellem komprimeringsforhold og hastighed afhængigt af komprimeringsniveau og format.
Sikkerheds- og sårbarhedsforanstaltninger
Følgende punkter kan overvejes for sikkerheds- og sårbarhedsforanstaltninger.
- Brug ikke ikke-betroet input direkte i filnavne eller stier.
- Brug kun Pickle med betroede kilder.
- Minimer udførelsesrettighederne, og giv kun de nødvendige tilladelser til processer, der håndterer filer.
- Brug midlertidige filer med
tempfile, og undgå at gemme almindelige filer i offentlige mapper.
Hvis brugerinput bruges i filstier, er normalisering og validering påkrævet. Brug for eksempel Path.resolve() og kontroller overordnede mapper.
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')- Vær særligt forsigtig ved brug af eksternt input som filstier i web-applikationer eller offentlige API'er.
Opsummering af almindelige mønstre
- Brug altid
with-sætningen (automatisk lukning). - Angiv eksplicit
encodingfor tekstdata. - Læs og skriv store filer i blokke.
- Indfør fillåsning for delte ressourcer.
- For kritiske opdateringer, brug det atomare mønster 'skriv til midlertidig fil → os.replace'.
- Bekræft altid og lav sikkerhedskopier før farlige handlinger (som sletning eller overskrivning).
- Normaliser og valider ved brug af ekstern input som filstier.
Sammendrag
Ved filoperationer er det vigtigt at bruge sikre og pålidelige teknikker, såsom brug af with-sætningen, eksplicit angivelse af kodning og atomar skrivning. Ved storskalabehandling eller parallel adgang er det nødvendigt at implementere låse- og loghåndteringssystemer for at forhindre datakorruption og konflikter. At balancere effektivitet og sikkerhed er nøglen til pålidelig filhåndtering.
Du kan følge med i ovenstående artikel ved hjælp af Visual Studio Code på vores YouTube-kanal. Husk også at tjekke YouTube-kanalen.