- 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 relativní cesty
path1 = Path("data/testing-folder")
print("relativní cesta:", path1)
# ukázka absolutní cesty
path2 = Path(r"C:\Windows")
print("absolutní cesta:", path2)
# ukázka testu, zda soubor existuje
if path2.exists():
print(f"soubor {path2} existuje")
if path1.exists():
print(f"složka {path1} existuje")
# ukázka i ve Windows
CWD: /home/reitezuz/cv19 HOME: /home/reitezuz <class 'pathlib.PosixPath'> <class 'pathlib.PosixPath'> relativní cesta: data/testing-folder absolutní cesta: C:\Windows složka data/testing-folder existuje
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")
full_path = home / download / file
print(full_path)
# další ukázka ... i string:
full_path = home / "data" / "q.exe"
print(full_path)
/home/reitezuz/Download/rickroll.mp4 /home/reitezuz/data/q.exe
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)
# další ukázka ... lepeni cesty
full_path = home.joinpath(download,file)
print(full_path)
full_path = download.joinpath("files","x.bin")
print(full_path)
/home/reitezuz/Download/rickroll.mp4 /home/reitezuz/Download/rickroll.mp4 Download/files/x.bin
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) # jmeno souboru s priponou
print("Stem: ", path.stem) # jmeno souboru bez pripony
print("Suffix: ", path.suffix) # jen pripona
print("Anchor: ", path.anchor) # cast cesty pred slozkami
print("Parent: ", path.parent) # nadrazena slozka
Celá cesta: /home/reitezuz/recept_na_rumove_pralinky.html Name: recept_na_rumove_pralinky.html Stem: recept_na_rumove_pralinky Suffix: .html Anchor: / Parent: /home/reitezuz
Vytváření, čtení, zápis souborů¶
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.
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
from pathlib import Path
path = Path("data/touch.html")
path.touch()
# ukázka textového kopírování s kontrolou
original_path = Path("data/rename.txt")
new_path = Path("data/rename1.txt")
if not new_path.exists():
new_path.write_text(original_path.read_text())
else:
print("existuje")
existuje
# ukázka binarniho kopírování
original_path = Path("data/rename.txt")
new_path = Path("data/rename2.txt")
if not new_path.exists():
new_path.write_bytes(original_path.read_bytes())
else:
print("existuje")
existuje
Přejmenování, kopírování a mazá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řejmenování s využitím with...:
from pathlib import Path
original_path = Path("data/rename1.txt")
html_path = original_path.with_suffix(".html")
new_stem_path = html_path.with_stem("newname")
new_name_path = new_stem_path.with_name("readme.md")
print(original_path)
print(html_path)
print(new_stem_path)
print(new_name_path)
original_path.replace(html_path)
print(original_path)
print(html_path)
data/rename1.txt data/rename1.html data/newname.html data/readme.md data/rename1.txt data/rename1.html
# přejmenování bez využití with...:
from pathlib import Path
html_path = Path("data/rename1.html")
txt_path = Path("data/rename1.txt")
print(txt_path)
print(html_path)
html_path.replace(txt_path)
print(txt_path)
print(html_path)
data/rename1.txt data/rename1.html data/rename1.txt data/rename1.html
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}")
# 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}")
# 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/rename.txt to data/rename.html Renamed data/rename.html to data/newname.html 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 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()
.
from pathlib import Path
src = Path("data/dontreadme.md")
if src.exists():
src.unlink()
Vytváření a mazání složek (adresářů)¶
Modul pathlib
má také metody pro vytváření a mazání složek:
.mkdir()
vytvoří novou složku. Nelze vytvořit více zanořených podsložek najednou..rmdir()
smaže prázdnou složku.
from pathlib import Path
path = Path("data/subfolder")
path.mkdir()
path = path / "subsubfolder"
path.mkdir()
# ukazka ošetření pokud už existuje
# ukázka jak zase složky smažu
from pathlib import Path
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.
from pathlib import Path
path = Path().cwd() / "data/testing-folder/"
for file in path.iterdir():
print(f"{file}\nFolder: {file.is_dir()} File: {file.is_file()}")
/home/reitezuz/cv19/data/testing-folder/place_for_testing_file_operations Folder: False File: True
# ukázka: vypsat jmeno a typ do tabulky:
from pathlib import Path
path = Path().cwd() / "data/testing-folder/"
for file in path.iterdir():
if file.is_file():
type= "File"
elif file.is_dir():
type = "Folder"
else:
type = "Other"
print(f"{file.name:35} {type}")
place_for_testing_file_operations File .ipynb_checkpoints Folder
from pathlib import Path
path = Path("data")
path_list = path.glob("t*.*")
for file in path_list:
print(file)
print("")
for file in path.glob("*.txt"):
print(file)
# ukázka ... trochu více
data/text.txt data/touch.html data/data.txt data/inventory.txt data/text.txt data/new_file.txt data/sinus.txt data/data_new.txt data/cisla.txt data/soubor.txt data/rename2.txt data/sin_values.txt data/rename3.txt data/jiny.txt data/pokemon.txt data/dontreadme.txt
Příklady¶
- Ve složce
data/testing-folder
vytvoř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
from pathlib import Path
new_folder = Path("data/testing-folder/text-files")
if not new_folder.exists():
new_folder.mkdir()
for i in range(20):
jmeno = f"file{str(i).rjust(2,'0')}.txt"
new_file = new_folder / jmeno
new_file.write_text(f"nějaký text\n{i}")
# vypsat soubory ve složce:
for file in new_folder.iterdir():
print(file.name, end = " ")
file00.txt file01.txt file02.txt file03.txt file04.txt file05.txt file06.txt file07.txt file08.txt file09.txt file10.txt file11.txt file12.txt file13.txt file14.txt file15.txt file16.txt file17.txt file18.txt file19.txt
- Soubory
.txt
vytvořené v minulém příkladě přejmenujte tak, aby měly příponu.md
.
# změna přípony
#html_path = original_path.with_suffix(".html")
#original_path.replace(html_path)
# Path, iterdir nebo glob, with_suffix, replace
from pathlib import Path
folder = Path("data/testing-folder/text-files")
for file in folder.glob("*.txt"):
new_name = file.with_suffix(".md")
file.replace(new_name)
- Smažte po sobě všechny soubory
.md
a také složkutext-files
.
# Path, iterdir, unlink, rmdir
from pathlib import Path
folder = Path("data/testing-folder/text-files")
for file in folder.iterdir():
file.unlink()
folder.rmdir()
# Pokud jsou tam skryté Jupyterovské soubory navíc
#... nešikovné řešení:
from pathlib import Path
folder = Path("data/testing-folder/text-files")
for file in folder.iterdir():
if file.is_file():
file.unlink()
if file.is_dir():
for file1 in file.iterdir():
file1.unlink()
file.rmdir()
folder.rmdir()
# Pokud jsou tam skryté Jupyterovské soubory navíc
#... lepší řešení pomocí rekurze:
from pathlib import Path
folder = Path("data/testing-folder/text-files")
def delete_rek(folder):
for file in folder.iterdir():
if file.is_file():
file.unlink()
if file.is_dir():
delete_rek(file)
folder.rmdir()
delete_rek(folder)
# Pokud jsou tam skryté Jupyterovské soubory navíc
#... řešení pomocí modulu shutil:
import shutil
# Pokud jsou tam skryté Jupyterovské soubory navíc
#... nešikovné řešení:
from pathlib import Path
folder = Path("data/testing-folder/text-files")
# shutil.rmtree(folder) # to by taky šlo :-)
for file in folder.iterdir():
if file.is_file():
file.unlink()
if file.is_dir():
shutil.rmtree(file)
folder.rmdir()
- Spočítejte kolik různých typů souborů existuje ve složce
data/example-files
a u každého typu též spočítejte, kolik takových souborů existuje.
# iterdir
folder = Path("data/example-files")
d = {}
#s = []
for file in folder.iterdir():
if not file.suffix in d:
d[file.suffix] = 1
else:
d[file.suffix] += 1
#s.append(file.suffix)
#print(file.suffix)
print(d)
#print(s)
{'.html': 22, '.md': 17, '.txt': 26}
- Ukázkové soubory ze složky
data/example-files
roztř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
.
# iterdirm split, parent, exists, mkdir, write_bytes, name
- Vypište celou strukturu složky
data/testing-folder
z 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 ...
# rekurze, iterdir, is_dir, name