Warning
This page is located in archive. Go to the latest version of this course pages. Go the latest version of this page.

Souborový systém

Pár rad, jak pracovat se souborovým systémem v Pythonu.

Ukázky pomocí staršího, ale stále podporovaného a používaného rozhraní pro práci se souborovým systémem budou uvedeny v levém sloupci. Toto rozhraní má také tu výhodu, že je podobné rozhraní pro práci se soubory v jazyku C a dalších.

Ukázky pomocí novějšího rozhraní, které nabízí modul pathlib, budou uvedeny v pravém sloupci. Rozhraní je modernější a mnoha lidem se s ním pracuje líp.

Práce s adresáři

Pravděpodobně budete chtít ve svých skriptech nějaká data načítat ze souborů nebo ukládat do souborů. Velmi často budete mít v jedné proměnné, např. fname, uloženo jméno souboru a v druhé proměnné, např. fpath, cestu, kde se má soubor nacházet. Abyste k souboru mohli přistoupit, musíte fpath a fname spojit správným oddělovačem, který se používá v OS, na němž právě pracujete. Na Unixech a Linuxech se jako oddělovač používá normální lomítko /, na Windows zpětné lomítko \, které se ovšem musí v Pythonských řetězcích zapisovat jako \\ (protože \ se používá k uvození speciálních znaků). V praxi si ovšem s detekcí operačního systému nemusíte dělat starosti, použijete-li vhodné nástroje.

Při použití funkcí z modulů os a os.path budou jednotlivé cesty a názvy souborů reprezentované prostými řetězci. Proměnná os.sep obsahuje ten správný separátor, ať už jste na kterémkoli OS. Takže následující kód

>>> import os
>>> fpath = 'cesta_k_souboru'
>>> fname = 'nazev_souboru'
>>> fpath + os.sep + fname
bude mít na Widnows výsledek
'cesta_k_souboru\\nazev_souboru'
zatímco na Linuxu
'cesta_k_souboru/nazev_souboru'

Můžeme také využít funkce os.path.join(). Příkaz

>>> os.path.join(fpath, fname)
bude mít na Windows i na Linuxu stejný výsledek, jako předchozí varianta využívající os.sep. Navíc se tato funkce také vypořádá s případem, kdy fpath už končí oddělovačem (tj. nezdvojí ho).

Při použití tříd a funkcí z modulu pathlib budou jednotlivé cesty reprezentované instancemi tříd PosixPath (Linux, Mac) nebo WindowsPath. Instanci správného typu ale v kódu vytvoříte pomocí třídy Path. Tyto třídy mají přetížený operátor /, který se používá ke spojování jednotlivých částí cest pomocí správného oddělovače. Takže následující kód

>>> from pathlib import Path
>>> fpath = Path('cesta_k_souboru')
>>> fname = 'nazev_souboru'
>>> fpath / fname
bude mít na Windows výsledek
WindowsPath('cesta_k_souboru/nazev_souboru')
zatímco na Linuxu
PosixPath('cesta_k_souboru/nazev_souboru')

Můžeme také využít metodu .joinpath(). Příkaz

>>> fpath.joinpath(fname)
bude mít na Windows i na Linuxu stejný výsledek, jako předchozí varianta využívající operátor /. Navíc se tato funkce také vypořádá s případem, kdy fpath už končí oddělovačem (tj. nezdvojí ho).

Uložení souboru do aktuálního adresáře

Váš program si bude chtít uložit nějaká data pro svou potřebu a pozdější využití. Logické umístění souboru s takovými daty je adresář, v němž se nachází váš program (příp. jeho podadresáře). Pravděpodobně vás napadne použít relativní cestu, díky níž se umístění souboru odvozuje od aktuálního adresáře. Pokud tedy z příkazové řádky, či z Pythonského interpretu spustíte svůj skript script.py, v němž zavoláte příkaz

f = open('data.txt', 'wt', encoding='utf-8')
opravdu se vedle vašeho skriptu script.py vytvoří ve stejném adresáři datový soubor data.txt. A to jsme přece chtěli, ne?

Problém nastává v okamžiku, kdy se váš skript script.py stane modulem, který importujete do dalších modulů a ty jej využívají. Pokud váš modul script.py importuje spuštěný skript z vyšší úrovně (“z nadřazeného adresáře”), není již aktuálním adresářem ten adresář, který obsahuje script.py, ale adresář, v němž sídlí ten skript, který byl spuštěn Pythonským interpretem. Soubor data.txt by byl vytvořen někde jinde - daleko od zamýšleného umístění.

Jak lze zajistit, aby se datový soubor vždy ukládal tam, kam chceme, tedy do stejného adresáře, kde je umístěn i náš script.py?

Pokud se soubor importuje jako modul, lze cestu k němu získat konstrukcí

fpath = os.path.dirname( os.path.abspath(__file__) ) 
Tato konstrukce však může někdy selhat (pokud např. budeme modul spouštět položkou Run z editoru IDLE, nebo pokud jej v Pythonu 2 budeme spouštět funkcí execfile() - v takovém případě totiž nedochází k importu modulu a nenastavuje se proměnná file).

Zcela univerzální postup představuje následující konstrukce využívající modul inspect:

import inspect
fpath = os.path.dirname( inspect.getfile( inspect.currentframe() ) )

courses/b4b33rph/tutorialy/python/filesystem.txt · Last modified: 2023/08/31 08:55 by xposik