Bestanden in de juiste modus openen en weer sluiten
Na deze les kun je
Lezen, vervangen, toevoegen en exclusief aanmaken onderscheiden.
Een geopende tekststream met with afsluiten.
De afgesproken inhoud en bestaande bestanden behouden.
Een bestand lezen is een andere afspraak dan de inhoud vervangen. Ook toevoegen aan een log en alleen een nieuw bestand aanmaken zijn verschillende handelingen. Je kiest die bedoeling wanneer je het bestand opent.
Openen geeft een stream
Met open vraag je een verbinding met een bestand aan. De stream die je terugkrijgt heeft methoden zoals readline en write. In tekstmodus gebruik je een tekencodering om tussen bytes en strings te vertalen.
Het eerste voorbeeld leest één regel met readline(). De newline blijft in de ontvangen string staan. Een leeg bestand levert bij deze leesactie een lege string.
De stream is ook na het lezen werkelijk gesloten
notes.txt
één
twee
first_line.py
with open("notes.txt", "r", encoding="utf-8") as stream:
print(stream.readline(), end="")
print(stream.closed)
Verwachte uitvoer
één
True
Een resource hoort een eindpunt te hebben
Een geopende stream moet ook worden gesloten. Het with-blok gebruikt daarvoor de contextmanager van het bestand. Na het verlaten van het blok sluit Python de stream, ook bij een return of een fout in het blok.
Je kent die lifecycle al van contextmanagers en fixtures. Het bestand is nu een echte toepassing daarvan. Buiten het blok kun je de eigenschap closed bekijken, maar je kunt dan niet meer verder lezen of schrijven met die gesloten stream.
Een open-aanroep kan zelf mislukken, bijvoorbeeld omdat een leesbestand ontbreekt. Dan is er nog geen stream om in het blok te gebruiken. De betreffende fout loopt naar de aanroeper, tenzij je bewust passende afhandeling toevoegt.
Vier verschillende bedoelingen
De modus vertelt wat je wilt doen. r leest een bestaand bestand; w schrijft vanaf een lege inhoud en kan een nieuw bestand maken. Met a voeg je aan het einde toe en met x vraag je exclusief een nieuw bestand aan.
Modus
Bestaand bestand
Ontbrekend bestand
r
Lezen
FileNotFoundError
w
Oude inhoud leegmaken en schrijven
Maken en schrijven
a
Aan het einde schrijven
Maken en schrijven
x
FileExistsError
Maken en schrijven
Het tweede voorbeeld laat drie schrijfkeuzes op hetzelfde lesbestand zien. Eerst vervangt het de oude regel, daarna voegt het een regel toe. De exclusieve aanmaak wordt vervolgens met een echte FileExistsError geweigerd.
Vervangen, toevoegen en exclusief maken geven ander gedrag
notes.txt
oud
write_modes.py
from pathlib import Path
with open("notes.txt", "w", encoding="utf-8") as stream:
stream.write("nieuw\n")
with open("notes.txt", "a", encoding="utf-8") as stream:
stream.write("extra\n")
print(Path("notes.txt").read_text(encoding="utf-8"), end="")
try:
with open("notes.txt", "x", encoding="utf-8") as stream:
stream.write("vervangen")
except FileExistsError as error:
print(type(error).__name__)
Verwachte uitvoer
nieuw
extra
FileExistsError
Veelgemaakte fout: openen voordat je wilt lezen
Een bestand in modus w openen kan de oude inhoud al leegmaken voordat je iets schrijft. Die modus gebruiken om eerst te kijken wat er stond, is daarom verkeerd. Kies voor lezen een leesmodus en voor bewust vervangen een schrijfmodus.
Write voegt ook geen automatische newline toe. Als twee aanroepen zonder scheidingstekens schrijven, komt hun tekst direct tegen elkaar te staan. Geef een gewenste regelovergang dus als onderdeel van de tekst mee.
De geopende stream kunnen volgen
De vier functies ontvangen een optionele opener die standaard de gewone open-functie is. Dat is hetzelfde idee als de ontvangen klok uit de vorige module. Je roept de meegegeven functie aan met het pad, de modus en encoding="utf-8".
De lesopener opent echte tijdelijke bestanden en kan de gemaakte stream daarna bekijken. Zo wordt gecontroleerd of de inhoud klopt en of de stream bij terugkeer daadwerkelijk gesloten is. Je hoeft daarvoor zelf geen rapporteur te schrijven.
Read_first geeft de eerste regel terug. De drie schrijffuncties geven na hun werk None terug en voegen geen eigen tekens toe. Een bestaand bestand moet bij exclusieve aanmaak ongewijzigd blijven, ook wanneer het leeg is.
Bij een fout midden in lezen of schrijven moet de stream ook sluiten. Een losse close na de actie wordt dan overgeslagen; with of try/finally voorkomt dat. Laat dezelfde oorspronkelijke fout door, zodat sluiten geen verzonnen succes oplevert.
AAN DE SLAG 0/4
1
Lezen en bij terugkeer sluiten
Vul read_first(path, *, opener=open) in. Open met de meegegeven opener in tekstleesmodus en UTF8, geef readline() terug inclusief eventuele newline en sluit de stream ook bij return. Ook na een fout tijdens lezen of schrijven sluit je de stream en geef je dezelfde oorspronkelijke fout door.
2
Bewust de inhoud vervangen
Vul write_note(path, text, *, opener=open) in. Gebruik de meegegeven opener in modus w met UTF8. Schrijf precies text, sluit de stream en geef None terug. Ook na een fout tijdens lezen of schrijven sluit je de stream en geef je dezelfde oorspronkelijke fout door.
3
Bestaande tekst aanvullen
Vul append_note(path, text, *, opener=open) in. Gebruik a met UTF8, schrijf precies text na bestaande inhoud, sluit en geef None terug. Ook na een fout tijdens lezen of schrijven sluit je de stream en geef je dezelfde oorspronkelijke fout door.
4
Alleen een nieuw bestand toestaan
Vul create_note(path, text, *, opener=open) in. Gebruik x met UTF8. Maak en sluit een nieuw bestand, maar laat FileExistsError doorlopen en behoud een bestaand bestand. Geef bij succes None terug. Ook na een fout tijdens lezen of schrijven sluit je de stream en geef je dezelfde oorspronkelijke fout door.
Onthouden
De modus kiest lezen, vervangen, toevoegen of exclusief aanmaken.
Gebruik with voor de levensduur van je echte bestandstream.
Kies UTF8 expliciet en schrijf precies de tekst die de aanroeper bedoelt.
Hierna lees je meerdere regels achtereen zonder alles vooraf in één string te verzamelen.