Se soubory v Python'u se na první pohled pracuje velmi podobně, jako kdekoliv jinde – soubor z daného umístění otevřeme, pracujeme s jeho obsahem a na konci ho zase spořádaně uzavřeme:
Výchozí mód je r
(tedy textový soubor otevřený pro čtení) a protože je pozičně na druhém místě, zdánlivě by pro textové soubory tedy stačilo psát open('CESTA', 'r')
nebo rovnou open('CESTA')
. Problém je v tom, že encoding je až třetí pojmenovaný parametr (druhým je nastavení mezipaměti buffering) a výchozí kódování je závislé na systému, takže open()
bez parametru encoding je v podstatě nepoužitelný (rozhodně nepřenosný).
Protože cestou se může stát mnoho nepředvídaného, je dobré se pojistit a soubor pro případ takových nenadálých událostí stejně pěkně zavřít.
Po staru to člověk dělal soustavou bloků try-finally
, ale v Python'u 3 je mnohem lepší použít příkaz with
pro vytvoření příslušného operačního kontextu (runtime context):
Uvnitř bloku máme pod identifikátorem f
k dispozici otevřený stream (aneb „proud dat“) a můžeme s ním úplně normálně pracovat. Jakmile kód v bloku proběhne, ať už úspěšně nebo neúspěšně, tak je stream automaticky uzavřen (a nemusíme se o to tudíž starat sami).
__enter__()
, při opuštění bloku pak __exit__()
. Blíže viz B.11.
Otevřený soubor (tedy stream, resp. „proud dat“; zde pro případ textového souboru) má mnoho zajímavých vlastností:
Na mnohé o souboru se můžeme ptát:
Všimněte si, že (dosud) otevřený soubor se patřičně hlásí jako nezavřený a naopak:
Plný konstruktor pro otevření souboru je nepřekvapivě dosti komplikovaný:
Teoreticky jediným povinným parametrem je sice pouze cesta k souboru (která možná trošku překvapivě nemusí být pouze řetězcem), se kterým chceme pracovat, ale jelikož výchozím módem je textový pro čtení, máme problém s přenositelností kódování*.
Další parametry pak jsou:
locale.getpreferredencoding(False)
.
Parametr closefd se může uplatnit v situaci, kdy cesta k souboru není zadána řetězcem, a parametr opener pak umožňuje i použít vlastní volatelný objekt pro otevření požadovaného cíle. Pro obé konzultujte prosím přímo oficiální dokumentaci.
Textový soubor (volitelně identifikovaný příznakem t
) můžeme otevřít v několika módech:
FileExistsError
, pokud soubor již existuje) a otevřen pro zápis
tr
, to jest textový soubor, pouze čtení.
Pro případ binárního souboru kombinujeme výše uvedené módy s příznakem b
(tedy např. br
otevře binární soubor pro čtení).
Z otevřeného proudu (streamu) je možno číst data několika různými způsoby. Základní představuje metoda read()
:
content = stream.read()
read()
bez parametrů (resp. s -1
) v podstatě ekvivalentní zavolání metody readall()
.
part = stream.read(ZNAKŮ|BAJTŮ)
Podobně jako u čtení z proudu máme pro zápis k dispozici především základní metodu:
stream.write(ŘETĚZEC|BAJTY)
Tato metoda provede zapsání daných znaků (pro případ textového souboru) nebo bajtů (pro případ binárního souboru):
Základní třídou pro vstup a výstup je třída IOBase
. Z ní dědí jak třída TextIOBase
pro práci s textovými soubory, tak třída RawIOBase
pro práci se soubory binárními.
Přitom mezi textovými a binárními soubory jsou dva, a to zcela zásadní, rozdíly:
\n
na Unixu a MacOS X+, \r\n
na Windows, \r
na MacOS 9-) na jednotné pracovní \n
(konverze je samozřejmě obousměrná), v binárních pochopitelně nikoli.
Pamatovat na rozdíl mezi bajty a znaky je přitom skutečně důležité:
Asi už tušíte, do jakých nesnází se dostanete, pokud se pokusíte na textovém proudu posouvat začátky čtení dalšího znaku do nesmyslných míst:
Kdybyste si neměli pamatovat nic jiného: Nikdy nemíchejte binární a textové proudy dohromady! ^_^
Zakončeme náš úvod do práce se soubory jednou velmi důležitou poznámkou:
Z důvodů vnitřní implementace a optimalizace práce s proudy (stream) probíhá veškerá komunikace přes tzv. mezipaměť (buffer), odkud jsou data přesouvána až podle požadavků systému, není-li programem vynuceno jinak.
V praxi to například v případě zápisu znamená, že data nemusí být před vyžádaným uzavřením proudu vůbec skutečně zapsána!
Někdy (podle způsobu práce i často) se nám může hodit vnutit systému zápis připravených dat dříve, než to zařídí uzavření proudu zavoláním jeho metody close() nebo ukončením práce v bloku with. A právě tuto činnost má na starosti metoda proudu flush().
sys.stdout
, což je – také ve výchozím nastavení – právě konzole. Vynucení výpisu dosud nabafrovaných dat pak zařídí podle verze Python'u buď nastavení stejnojmenného parametru přímo na funkci print() (Python 3.3+)..
Jak jsme zmiňovali už na prvním slajdu, historická pozice kódování textového souboru až jako třetího pojmenovaného parametru plus neexistující konsenzus pro výchozí kódování nám ztěžují práci se soubory. A tím parametrem, kvůli kterému musíme vždy vypisovat encoding= je právě parametr řídící způsob práce s mezipamětí: buffering
Jeho možná nastavení jsou následující:
Není-li atribut buffering= uveden (a má tak výchozí hodnotu -1), nastoupí heuristika:
isatty()
vrací True
) je bafrování nastaveno na řádkové;