Cvičení č. 19 rozšířené o poznámky ze cvičení a řešení některých příkladů (ZS 2025/26)¶
- Otevření souboru pomocí
open(). - Čtení dat pomocí
read(),readlines(). - Zápis do souboru pomocí
write()neboprint(). - Uzavření souboru pomocí
close().
Práce s adresářovou a souborovou strukturou¶
Práce s adresáři v Pythonu může být komplikovaná a bývá nutné použít více importovaných balíčků. Mimojiné z tohoto důvodu byl vytvořen balíček pathlib, který práci dost zjednodušuje a umožňuje lehce psát multiplatformní skripty pro různé operační systémy. Systémy Windows používají pro zápis cesty k souboru odlišnou syntaxi oproti systémům Linux a MacOS.
Příklad cesty ve Windows: C:\Users\billgates\Documents\chemtrails.txt
Příklad cesty v Linuxu: /home/linustorvalds/linuxftw.txt
Příklad cesty v MacOS: /Users/stevejobs/howtowearasweater.txt
Pro použítí pathlib je nutné tento modul importovat pomocí import pathlib. Případně si můžeme vybrat, které součásti modulu chceme použít. Například from pathlib import Path importuje pouze součást pro práci s cestami.
Modul pathlib je objektově orientovaný, což přispívá k jednoduchému použití.
Path a dostupné metody¶
Path má přímo dostupné základní metody pro zjištění aktuální pracovní složky a také domovského adresáře. Podle použitého operačního systému bude návratová hodnota buď objekt WindowsPath nebo PosixPath. Implementace uvnitř se liší, ale navenek (pro naše použití) jsou identické.
Path.cwd()vrátí objekt s aktuální pracovní složkou.Path.home()vrátí objekt s cestou do domovské složky.
from pathlib import Path
path = Path.cwd()
home = Path.home()
print("CWD:", path)
print("HOME:", home)
print(type(path), type(home))
# ukázka i ve windows
CWD: /home/user/zpro-2025-public.git HOME: /home/user <class 'pathlib._local.PosixPath'> <class 'pathlib._local.PosixPath'>
Objekt Path lze vytvořit také z libovolné cesty uložené ve stringu. Zde je dobré použít raw string, ve kterém se neprovádí escapování, takže můžeme v klidu psát i zpětná lomítka jako normální znak.
path = Path(r"C:\Windows")(Windows)path = Path("/users/hatsunemiku")(Linux/MacOs)
pathlib také dovoluje spojování cest do jedné. K tomu může například posloužit operátor /, který známe jako dělení.
home = Path.home()
download = Path("Download")
file = Path("rickroll.mp4")
print(home, download, file)
/home/user Download rickroll.mp4
full_path = home / download / file
print(full_path)
/home/user/Download/rickroll.mp4
# ukázka: spojování i se stringy
# relativní cesta
path = Path("fotky") / "Praha" / "can121.jpg"
# path = "dir" / "moje" / "muj.txt" # nejde, chyba (jeden z argumentů musí být Path)
print(path)
fotky/Praha/can121.jpg
Pokud se vám tento zápis nelíbí, lze též použít metodu joinpath(), která bere jako parametry stringy nebo objekty Path.
full_path2 = Path.home().joinpath("Download", Path("rickroll.mp4"))
print(full_path2)
# rozšířená ukázka: všechny argumenty typu Path
full_path2 = path.joinpath(download, file)
print(full_path2)
# rozšířená ukázka: všechny argumenty typu str
full_path2 = path.joinpath("Download", "rickroll.mp4")
print(full_path2)
/home/user/Download/rickroll.mp4 fotky/Praha/can121.jpg/Download/rickroll.mp4 fotky/Praha/can121.jpg/Download/rickroll.mp4
Součásti cesty¶
Cestu ke složce nebo souboru lze v operačních systémech rozdělit na několik částí, např. přípona souboru, jméno souboru, cesta k němu, atd. pathlib získávání těchto částí zjednodušuje.
.name: Vrací jméno souboru bez cesty..stem: Vrací jméno souboru bez přípony..suffix: Vrací příponu.anchor: Část cesty před složkami..parent: Vrací složku, ve které je soubor, nebo nadřazenou složku dané složce.
from pathlib import Path
path = Path.home() / "recept_na_rumove_pralinky.html"
print("Celá cesta:", path)
print("Name:", path.name)
print("Stem:", path.stem)
print("Suffix:", path.suffix)
print("Anchor:", path.anchor)
print("Parent:", path.parent)
Celá cesta: /home/user/recept_na_rumove_pralinky.html Name: recept_na_rumove_pralinky.html Stem: recept_na_rumove_pralinky Suffix: .html Anchor: / Parent: /home/user
Přejmenování a kopírování souborů¶
Pro nahrazení jména souboru nebo jeho přípony něčím novým lze využít následující metody objektu Path:
.with_suffix("nová přípona")v cestě k souboru nahradí starou příponu za novou..with_name("nové jméno souboru včetně přípony")v cestě k souboru nahradí celé jméno souboru za nové..with_stem("nové jméno souboru")nahradí v cestě původní jméno za nové, příponu zanechá.
Následně je třeba použít metodu .replace(), aby se změny provedly na disku. Více v následujícím příkladu.
# přesunu soubor jinam
from pathlib import Path
original_path = Path("data/text.txt")
new_path = Path.cwd() / "text.txt"
original_path.replace(new_path)
print(f"Moved {original_path} to {new_path}")
Moved data/text.txt to /home/user/zpro-2025-public.git/text.txt
# a zase zpět
original_path, new_path = new_path, original_path
original_path.replace(new_path)
print(f"Moved {original_path} to {new_path}")
Moved /home/user/zpro-2025-public.git/text.txt to data/text.txt
from pathlib import Path
original_path = Path("data/rename.txt")
# změna přípony
html_path = original_path.with_suffix(".html")
original_path.replace(html_path)
print(f"Renamed {original_path} to {html_path}")
Renamed data/rename.txt to data/rename.html
# změna jména
new_stem_path = html_path.with_stem("newname")
html_path.replace(new_stem_path)
print(f"Renamed {html_path} to {new_stem_path}")
Renamed data/rename.html to data/newname.html
# změna celého jména včetně přípony
new_name_path = new_stem_path.with_name("readme.md")
new_stem_path.replace(new_name_path)
print(f"Renamed {new_stem_path} to {new_name_path}")
Renamed data/newname.html to data/readme.md
Při přejmenovávání souborů je případný existující soubor automaticky přepsán. Je třeba na to dávat pozor. Lze si ale pomoci detekcí, zda soubor s novým jménem existuje, pomocí metody .exists(), která vrací True nebo False.
from pathlib import Path
src = Path("data/readme.md")
dest = src.with_suffix(".exe")
if src.exists() and not dest.exists():
src.replace(dest)
Kopírování souborů je trošku komplikovanější, protože pathlib nemá přímou podporu. Ale lze to vyřešit pomocí metod .read_bytes() a .write_bytes().
from pathlib import Path
src = Path("data/readme.exe")
dest = src.with_name("dontreadme.md")
dest.write_bytes(src.read_bytes())
39
Soubory lze smazat pomocí metody .unlink().
Složky lze mazat pomocí metody .rmdir().
from pathlib import Path
src = Path("data/dontreadme.md")
if src.exists():
src.unlink()
p = Path("data")
# p.rmdir() # chyba ... adresář není prázdný
Vytváření, čtení, zápis souborů a složek¶
Modul pathlib dovoluje i zjednodušený zápis a čtení souborů. K tomu slouží metody třídy Path.
.read_text()otevře soubor v textovém režimu a načte obsah do stringu..read_bytes()otevře soubor v binárním režimu a načte jeho obsah jako byty..write_text()otevře soubor v textovém režimu a zapíše do něj text..write_bytes()otevře soubor v binárním režimu a zapíše binární data..touch()vytvoří prázdný soubor. Pokud existuje, změní čas modifikace na aktuální čas..mkdir()vytvoří novou složku. Nelze vytvořit více zanořených podsložek najednou.
Tyto metody rovnou soubor otevírají a zavírají. Není třeba se o to starat.
from pathlib import Path
textfile = Path("data/text.txt")
file_contents = textfile.read_text()
print(file_contents)
Okolo lesa pole lán, hoj jede, jede z lesa pán, na vraném bujném jede koni, vesele podkovičky zvoní, jede sám a sám. A před chalupou s koně hop a na chalupu: klop, klop, klop! „Hola hej! otevřte mi dvéře, zbloudil jsem při lovení zvěře, dejte vody pít!“
from pathlib import Path
data = ["Snorlax", "Bulbasaur", "Mewtwo", "Smoochum"]
new_text_file = Path("data/pokemon.txt")
new_text_file.write_text("\n".join(data))
33
new_text_file.touch()
from pathlib import Path
path = Path("data/touch.html")
path.touch()
# podadresáře je třeba vytvářet a mazat postupně:
from pathlib import Path
path = Path("data/subfolder")
if not path.exists():
path.mkdir()
path = path / "subsubfolder"
if not path.exists():
path.mkdir()
path = Path("data/subfolder/subsubfolder")
if path.exists():
path.rmdir()
path = path.parent
if path.exists():
path.rmdir()
Obsah složky (adresáře)¶
Pro získání obsahu složky lze použít metodu .glob(), která podle zadaného filtru vrátí odpovídající položky. Případně lze procházet složku pomocí metody .iterdir().
Path též dovoluje zjišťovat, o jaký typ cesty se jedná. Zda je to soubor, složka, symbolický link nebo další.
.is_dir()vrátíTrue, pokud se jedná o složku (adresář)..is_file()vrátíTrue, pokud se jedná o soubor..is_symlink()vrátíTrue, pokud se jedná o symbolický link.
# zjišťovací funkce:
path = Path("data")
path.is_file(), path.is_dir(), path.is_symlink()
(False, True, False)
from pathlib import Path
path = Path().cwd() / "data"
for file in path.iterdir():
print(f"{file.name:20} Folder: {file.is_dir()} File: {file.is_file()}")
inventory_en.csv Folder: False File: True readme.exe Folder: False File: True touch.html Folder: False File: True example-files Folder: True File: False pokemon.txt Folder: False File: True .ipynb_checkpoints Folder: True File: False text.txt Folder: False File: True inventory.txt Folder: False File: True inventory.csv Folder: False File: True testing-folder Folder: True File: False text_en.txt Folder: False File: True argparse_test.py Folder: False File: True data.txt Folder: False File: True data_en.txt Folder: False File: True
# ukázka: iterdir() vrací generátor
it = path.iterdir()
print(it)
print(next(it))
print(next(it))
list(it)
<map object at 0x7f96a607e230> data/inventory_en.csv data/readme.exe
[PosixPath('data/touch.html'),
PosixPath('data/example-files'),
PosixPath('data/pokemon.txt'),
PosixPath('data/.ipynb_checkpoints'),
PosixPath('data/text.txt'),
PosixPath('data/inventory.txt'),
PosixPath('data/inventory.csv'),
PosixPath('data/testing-folder'),
PosixPath('data/text_en.txt'),
PosixPath('data/argparse_test.py'),
PosixPath('data/data.txt'),
PosixPath('data/data_en.txt')]
from pathlib import Path
path_list = Path("data").glob("*.txt")
path_list
<map at 0x7fe92eeefa90>
from pathlib import Path
path_list = Path("data").glob("*.txt")
for file in path_list:
print(file)
data/pokemon.txt data/text.txt data/inventory.txt data/text_en.txt data/data.txt data/data_en.txt
Příklady¶
- Ve složce
data/testing-foldervytvořte novou podsložku se jménemtext-files. V této nové složce vytvořte 20 textových souborů se jménemfile##.txt, kde##odpovídá číslům 0 až 19. Do souboru zapište nějaký neprázdný text.
# Path, mkdir, /, write_text
s = "8"
s.rjust(2,"0")
'08'
# relativní vs. celá cesta k tomu samému souboru:
path_dir = Path.cwd() / Path("data/testing-folder")
path_dir.exists(), path_dir
(True, PosixPath('/home/user/zpro-2025-public.git/data/testing-folder'))
path_dir = Path("data/testing-folder")
path_dir.exists(), path_dir
(True, PosixPath('data/testing-folder'))
path_dir = Path("data/testing-folder/text-files")
if not path_dir.exists():
path_dir.mkdir()
for i in range(20):
if i < 10:
i = "0"+ str(i)
path_file = path_dir / f"file{str(i)}.txt"
path_file.write_text("ahoj")
for p in path_dir.iterdir():
print(p.name, p.read_text())
file02.txt ahoj file03.txt ahoj file07.txt ahoj file06.txt ahoj file11.txt ahoj file05.txt ahoj file13.txt ahoj file04.txt ahoj file17.txt ahoj file10.txt ahoj file18.txt ahoj file01.txt ahoj file19.txt ahoj file15.txt ahoj file14.txt ahoj file16.txt ahoj file09.txt ahoj file12.txt ahoj file08.txt ahoj file00.txt ahoj
- Soubory
.txtvytvořené v minulém příkladě přejmenujte tak, aby měly příponu.md.
# Path, glob nebo iterdir, with_suffix, replace
path_dir = Path("data/testing-folder/text-files")
#for path_file in path_dir.iterdir():
for path_file in path_dir.glob("*.txt"):
path_new = path_file.with_suffix(".md")
#print(path_file, path_new)
path_file.replace(path_new)
- Smažte po sobě všechny soubory
.mda také složkutext-files.
# iterdir nebo glob, unlink, rmdir
path_dir = Path("data/testing-folder/text-files")
for path_file in path_dir.iterdir():
path_file.unlink()
if path_dir.exists():
path_dir.rmdir()
# remove hidden files:
path_hidden = Path("data/testing-folder/text-files/.ipynb_checkpoints")
if path_hidden.exists():
for p in path_hidden.iterdir():
print(p)
p.unlink()
path_hidden.rmdir()
- Spočítejte kolik různých typů souborů existuje ve složce
data/example-filesa u každého typu též spočítejte, kolik takových souborů existuje.
# iterdir, suffix
path_dir = Path("data/example-files")
for p in path_dir.iterdir():
print(p.suffix) # d[p.suffix] += 1
d = {}
for path in Path("data/example-files").iterdir():
if path.suffix not in d:
d[path.suffix] = 0
d[path.suffix] +=1
d
{'.html': 22, '.txt': 26, '.md': 17}
- Ukázkové soubory ze složky
data/example-filesroztřiďte podle roku a měsíce uvedeného ve jméně souboru (formát jména jedata-YYYY-MM-DD.EXT) do složek s číslem roku a měsíce. Roztříděné soubory nakopírujte do složkydata/testing-folder.
Příklad: Soubor data-2002-01-01.md nakopírujeme do složky data/testing-folder/2002/01.
# iterdir, /, exists, mkdir, name, read_bytes, write_bytes
- Vypište celou strukturu složky
data/testing-folderz minulého příkladu včetně souborů v následujícím formátu (včetně odsazení):
2000
01
data-2000-01-01.html
...
02
data-2000-02-01.txt
...
2001
01
data ...
# iterdir, is_dir, name
Shrnutí kapitoly¶
# create Path
from pathlib import Path
path0 = Path.cwd()
path_home = Path.home()
path = Path("data/a")
path1 = path / "text.txt"
path2 = path0.joinpath(path1)
print(path0, path, path1)
# atributs
print("Celá cesta:", path)
print("Name:", path.name)
print("Stem (jméno bez přípony):", path.stem)
print("Suffix:", path.suffix)
print("Anchor:", path.anchor)
print("Parent:", path.parent)
# tests
print(path1.exists())
print(path1.is_file())
print(path1.is_dir())
# rename
path2 = path1.with_suffix(".html")
path2 = path1.with_name("new.html")
path2 = path1.with_stem("new")
if path1.exists() and not path2.exists():
path1.replace(path2)
#delete
if path2.exists() and path2.is_file():
path2.unlink()
#read-write:
path1.touch()
path1.write_text("ahoj")
text = path1.read_text()
path2.write_bytes(path1.read_bytes()) # copy
#directory
if path2.exists() and path2.is_dir():
path2.rmdir()
if not path2.exists():
path2.mkdir()
gen1 = Path("data").iterdir()
gen2 = Path("data").glob("*")