Filoperationer i Python
Den här artikeln förklarar filoperationer i Python.
Med "säkerhet", "effektivitet" och "läsbarhet" i åtanke förklarar denna guide steg för steg, från grunderna till praktiska tekniker.
YouTube Video
Filoperationer i Python
Filhantering är en grundläggande färdighet, från små skript till storskaliga applikationer.
Öppna och stänga filer
Låt oss först titta på exempel på att läsa och skriva textfiler. Genom att använda with-satsen (kontexthanterare) säkerställs att filen stängs korrekt.
Följande kod öppnar en textfil, läser dess innehåll och bearbetar det rad för rad.
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())- Genom att explicit ange
encoding="utf-8"minskar plattformsberoende problem. - Även med stora filer är
for line in fminnesvänligt.
Skriva (skriva över och lägga till)
Var uppmärksam på läget när du skriver till filer. w används för att skriva över, a används för att lägga till. Använd också with-satsen när du skriver till filer.
Följande kod visar grundläggande exempel på att skriva över och lägga till.
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")- Den här koden skriver text till
output.txtoch lägger sedan till mer text i samma fil. Läget"w"skriver över filen, medan"a"lägger till en ny rad i slutet av det befintliga innehållet. - Om du behöver spola (flush), anropa
flush(), men vanligtvis spolas innehållet automatiskt när kontexten avslutas. - Om flera processer eller trådar kan skriva samtidigt måste du överväga exklusiv kontroll, såsom fillåsning.
Läsa och skriva binär data
Bilder och komprimerade filer hanteras i binärt läge (rb eller wb). Till skillnad från textläge ignoreras encoding i binärt läge.
Följande kod läser en binär fil och kopierar den till en annan fil i binärt läge.
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)- När du hanterar stora binärfiler, undvik att läsa allt på en gång med
read(); att läsa och skriva i segment är mer minnesvänligt.
Exempel på hantering av stora filer i segment
För stora filer som inte får plats i minnet, läs och skriv dem i segment med fast storlek. Eftersom det är I/O-beroende är det användbart att justera buffertstorleken.
Följande kod kopierar en fil i 64KB-stora segment. Detta arbetar snabbt samtidigt som minnesanvändningen hålls låg.
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 justera segmentstorleken beroende på egenskaperna hos ditt nätverk eller din disk. På SSD-enheter fungerar ofta en något större segmentstorlek bättre.
Exempel på att använda argumentet buffering
Genom att ange argumentet buffering i funktionen open() kan du kontrollera buffertstorleken som används internt av Python. Detta gör att du kan optimera in- och utmatningseffektiviteten ytterligare.
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)- Om du sätter värdet på
bufferingtill 0 utförs I/O utan buffring; 1 möjliggör radbuffring, medan värden på 2 eller högre använder en buffert av angiven storlek i byte. - Generellt sett är standardvärdet tillräckligt eftersom operativsystemet effektivt hanterar cachning, men att justera denna parameter kan vara effektivt för mycket stora filer eller speciella enheter.
Moderna filoperationer med Pathlib
Standardmodulen pathlib gör hanteringen av sökvägar mer intuitiv. Det förbättrar läsbarheten och säkerheten jämfört med sökvägar som strängar.
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)- Den här koden visar hur du skapar en katalog med
pathlib, skriver till en textfil och läser dess innehåll. Med ettPath-objekt kan du hantera sökvägar både intuitivt och säkert. Pathhar smidiga API:er somiterdir()ochglob(). Du kan skriva kod utan att oroa dig för sökvägsavgränsare mellan olika operativsystem.
Temporära filer och kataloger (tempfile)
Temporära filer kan skapas säkert med tempfile. Detta undviker race conditions samt namnkonflikter.
Följande kod visar ett exempel på hur man skapar temporär data med hjälp av en temporär 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- Denna kod skapar en temporär fil, skriver och läser data och tar automatiskt bort filen när
with-blocket avslutas. Medtempfile.NamedTemporaryFilekan du hantera temporära filer säkert och utan konflikter. Eftersomdelete=Trueär angivet tas filen bort automatiskt. - På Windows kanske du inte kan öppna filen från ett annat handtag direkt, så du kan ange
delete=Falseoch själv hantera borttagningen.
shutil: Hög nivå-operationer för att kopiera, flytta och ta bort
Rekursiv kopiering, flyttning och radering av filer och kataloger är enkelt 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.copy2kopierar även metadata (som ändringstid).moveförsöker flytta filen även om byta namn inte kan användas.rmtreeär en farlig åtgärd, så bekräfta och säkerhetskopiera alltid före radering.
Filmetadata (os.stat) och hantering av behörigheter
Filstorlek, ändringstid och behörigheter kan läsas och ändras med os och stat.
Följande kod hämtar grundläggande filinformation med os.stat och ändrar behörigheter 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)- Behörigheter fungerar olika på POSIX- och Windows-system. Om plattformsoberoende är viktigt, använd hög nivå-API:er eller lägg till villkorlig hantering.
Fillåsning (exklusiv kontroll) — Skillnader mellan Unix och Windows
Exklusiv kontroll krävs när flera processer parallellt får åtkomst till samma fil. UNIX använder fcntl och Windows använder msvcrt.
Följande kod använder fcntl.flock på UNIX-system för att erhålla ett exklusivt lås vid 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)- Denna kod får ett exklusivt lås med
fcntl.flockpå UNIX-liknande system för att skriva säkert och förhindra samtidiga skrivningar till filen. Släpp alltid låset efter bearbetning för att tillåta åtkomst av andra processer. - På Windows, använd
msvcrt.locking(). För mer avancerad användning, överväg externa bibliotek somportalockerellerfilelock.
Atomära filskrivningsmönster
För att undvika filskador vid uppdateringar, skriv till en temporär fil och ersätt den med os.replace vid framgång.
Genom att skriva till en temporär fil och sedan ersätta den undviks filskador om ett avbrott inträffar.
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 utför en atomär ersättning inom samma filsystem. Observera att atomicitet inte garanteras över olika monterade filsystem.
Snabb åtkomst med mmap (för storskalig data)
För slumpmässig åtkomst till stora filer förbättrar mmap I/O-prestandan. Det handlar främst om binära operationer.
Följande kod minnesmappar en fil och läser eller skriver specifika byteintervall. Var försiktig vid ändring av filstorleken.
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()- Den här koden mappar en binär fil till minnet med
mmapoch utför direkta byte-nivå läs-/skrivoperationer. Minnesmappning möjliggör snabb slumpmässig åtkomst till stora datamängder. mmapär effektivt, men felanvändning kan leda till datakonsistensproblem. Anropaflush()för att synkronisera vid behov.
CSV / JSON / Pickle: Läsning och skrivning per format
Specifika dataformat har egna moduler. Använd csv för CSV, json för JSON och pickle för att spara Python-objekt.
Följande kod visar grundläggande exempel på att läsa och skriva CSV och JSON samt använda Pickle. Eftersom Pickle kan köra godtycklig kod, undvik att läsa in data från opålitliga källor.
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 rekommenderas att ange
newline=""för CSV för att undvika extra tomma rader på Windows. Medensure_ascii=Falseförblir UTF-8-tecken i JSON läsbara.
Direkt läsning och skrivning av komprimerade filer (gzip / bz2 / zipfile)
Direkt hantering av gzip och zip kan spara diskutrymme. Standardbiblioteket innehåller motsvarande moduler.
Följande kod är ett enkelt exempel på att läsa och skriva gzip-filer som 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())- Det finns en avvägning mellan komprimeringsgrad och hastighet beroende på komprimeringsnivå och format.
Säkerhets- och sårbarhetsåtgärder
Följande punkter kan beaktas för säkerhets- och sårbarhetsåtgärder.
- Använd inte opålitlig indata direkt i filnamn eller sökvägar.
- Använd Pickle endast med pålitliga källor.
- Minimera körningsbehörigheter och ge endast minsta möjliga rättigheter till processer som hanterar filer.
- Använd temporära filer med
tempfileoch lagra inte vanliga filer i publika kataloger.
Om du använder användarindata i filsökvägar krävs normalisering och validering. Använd till exempel Path.resolve() och kontrollera överordnade kataloger.
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')- Var särskilt försiktig om du använder extern indata som filsökvägar i webbappar eller publika API:er.
Sammanfattning av vanliga mönster
- Använd alltid
with-satsen (automatisk stängning). - Specificera alltid
encodingför textdata. - Läs och skriv stora filer i segment.
- Inför filslåsning för delade resurser.
- För kritiska uppdateringar, använd det atomära mönstret 'skriv till temporär fil → os.replace'.
- Bekräfta alltid och skapa säkerhetskopior innan farliga åtgärder utförs (såsom radering eller överskrivning).
- Normalisera och validera när extern inmatning används som filsökväg.
Sammanfattning
För filoperationer är det viktigt att använda säkra och pålitliga metoder som with-satser, explicit kodningsangivelse och atomära skrivningar. För storskalig bearbetning eller parallell åtkomst är det nödvändigt att implementera låsning och logghanteringssystem för att förhindra datakorruption och konflikter. Att balansera effektivitet och säkerhet är nyckeln till tillförlitliga filoperationer.
Du kan följa med i artikeln ovan med hjälp av Visual Studio Code på vår YouTube-kanal. Vänligen kolla även in YouTube-kanalen.