Práce se soubory
Funkce open()
Tato funkce slouží k vytvoření objektu typu file (tento objekt je její návratovou hodnotou), který poskytuje metody pro práci se soubory.
Mód je řetězec, který určí jak se bude se souborem zacházet. Může obsahovat následující hodnoty (podobně jako v jazyku C):
Typ | Význam |
---|---|
'r' | Soubor bude otevřen pro čtení. Pokud neexistuje, nastane výjimka IOError |
'r+' | Soubor bude otevřen pro čtení a zápis. Pokud neexistuje, nastane výjimka IOError. |
'w' | Soubor bude otevřen pro zápis. Existující soubor bude zkrácen na nulovou délku, neexistující bude vytvořen. |
'a' | Soubor bude otevřen pro zápis na konec souboru (append). Neexistující soubor bude vytvořen. |
'b' | Soubor bude otevřen v binárním režimu. (Znaky nového řádku "\n" nebudou převáděny na platformě závislé "\r", "\r\n" atd.). |
't' | Soubor bude otevřen v textovém režimu. Toto je defaultní volba, takže se nemusí uvádět. Volby 'b' a 't' pochopitelně není možné použít společně. |
S těmito znalostmi již můžete napsat funkci, která bude vracet
True
v případě existence souboru a False
v případě neexistence souboru. Jediný argument této funkce bude název
zkoumaného souboru.
try:
soubor = open(nazev, 'r')
except IOError:
return False
else:
soubor.close()
return True
>>> fileexist('/tmp/pokus.txt')
False
Pokud vás překvapily lomítka v názvu souboru, pak vězte, že v Linuxu je to normální. Proč jsou v DOSu obráceně ví snad jen Bill Gates. Adresář /tmp/ je také v každém Linuxu. Pokud pracujete s jiným operačním systémem, změňte adresář i lomítka dle libosti.
Python má samozřejmě vlastní funkce na práci se soubory, prostudujte
si modul os.path
(hned co se naučíte pracovat s moduly).
Metody objektu file
V kapitole o objektech jsem vysvětlil, co
jsou to metody. Funkce open()
vrací file objekt
a
pomocí jeho metod se pracuje se souborem.
Metoda close()
Metoda close()
má jediný smysl života: uzavírá spojení se
souborem. Teprve po použití metody close()
máte jistotu, že
všechny změny provedené v souboru byly správně uloženy. Také tím
uvolníte systémové prostředky počítače, takže na ní nezapomínejte.
Pokud na ní zapomenete, nemusí to být hned tragédie. Po skončení programu to za vás udělá operační systém. Pamatujte ovšem na to, že množství otevřených souborů programem v jeden okamžik je limitováno.
V předchozím příkladě by neměl chybět příkaz
soubor.close()
po úspěšném otevření souboru (v ostatních
případech nebyl soubor otevřen, takže není co zavírat).
Metoda write()
Metoda write()
zapíše do souboru data. Pokud je soubor otevřen
v textovém režimu (defaultní možnost, když neuvedete mód 'b'), pak se konec
řádku "\n" převádí na platformě závislý (tj. ve Windows "\r\n", v Linuxu
"\n" …).
Vyzkoušíme na příkladě.
V příkladě otevřeme soubor v aktuálním adresáři jménem pokus.txt.
Pokud nebude existovat, vytvoří se. Pak zapíšeme na konec souboru text
Hello World a konec řádku. Nakonec soubor uzavřeme, aby se změny
zapsali na disk a uvolnili se zdroje pro práci se souborem.
soubor.write('Hello World\n')
soubor.close()
Pokud tyto příkazy zadáte dvakrát, bude v souboru pokus.txt zapsáno Hello World dvakrát, vždy na nové řádce. To proto, že v řetězci 'Hello World\n' je znak konce řádky (speciální znak '\n').
Metoda readlines()
Metoda readlines()
vrátí seznam, jehož jednotlivými
položkami jsou všechny řádky souboru.
Vytvořte soubor pokus.txt, který bude obsahovat následující:
Prvni radka Druha radka Treti radka Ctvrta radka
Jeho obsah pak zjistíte takto:
s = open("pokus.txt",'r')
radky = s.readlines()
except IOError as ex:
print('Chyba prace se souborem')
else:
type(radky)
print(radky)
finally:
s.close()
<type 'list'>
['Prvni radka\n', 'Druha radka\n', 'Treti radka\n', 'Ctvrta radka\n']
Všiměnte si, že jsou řádky načteny i se speciálním znakem konec
řádku '\n'. Toho se můžete zbavit zavoláním metody .rstrip("\n")
na každém načteném řádku.
Metoda readline()
Metoda readlines()
načte naráz celý soubor. To může být trochu nešikovná při práci s velkými soubory
(mít celý soubor v paměti může být náročné). Metoda readline()
načte jen jeden řádek a vrátí jej jako
řetězec (i s "\n" na konci). Při druhém volání načte druhý řádek, atd. Pokud se dostane
na konec souboru, vrací prázdný řetězec (Na konci vrátí "", zatímco prázdný
řádek uprostřed souboru bude obsahovat "\n").
Přes objekt file
lze iterovat, jako by to byl seznam. V každé
iteraci se vrací jedna načtená řádka. Jde o pohodlnější způsob téhož, čehož
dosáhnete pomocí metody readline()
.
>>> for line in s:
nacteno = 'Načteno: %s' % line
# print nacteno, # Python 2.7
print(nacteno, end="") # Python 3.0
Načteno: Prvni radka
Načteno: Druha radka
Načteno: Treti radka
Načteno: Ctvrta radka
Metoda read()
Metoda read()
načte celý soubor, ale nerozdělí jej do seznamu podle nových řádek
jako metoda readline()
.
Navíc může mít argument typu int (celé číslo),
který určí maximální počet načtených bajtů.
Její chování ukáží na souboru pokus.txt z předchozího příkladu.
>>> s = open('pokus.txt',"r")
>>> while line:
line = s.read(6)
nacteno = 'Načteno: %s' % line
# print nacteno, # Python 2.7
print(nacteno, end=" ") # Python 3.0
Načteno: Prvni Načteno: radka
Načteno: Druha Načteno: radka
Načteno: Treti Načteno: radka
Načteno: Ctvrta Načteno: radka Načteno:
Načteno: >>>
V příkladě jsem využil toho, že prázdný řetězec je chápán jako False. Za předposledním Načteno je schovává znak '\n', za posledním Načteno je již prázdný řetězec (proto je >>> na stejné řádce).
Metody tell() a seek()
Metoda tell()
vrací aktuální pozici v souboru v bytech.
Její návratovou hodnotou je typ int v rozsahu <0,N-1>, kde N
je velikost souboru v bytech.
Metoda seek(pocet, pozice)
posune aktuální pozici v souboru o pocet bytů a to od místa
pozice. Pokud je pocet záporná hodnota, pak se posune
pocet bytů pozice nazpět. Pozice je typu int a může
nabývat následujících hodnot:
Hodnota pozice | Význam | Omezení |
---|---|---|
0 | Začátek souboru | |
1 | Aktuální pozice | Funguje jen v binárním režimu. |
2 | Konec souboru | Funguje jen v binárním režimu. |
Jen tak mimochodem, nebylo by místo čísel lepší používat výčtový typ?. Výčtový typ je v Pythonu až od verze 3.4, tak kdo ví, třeba se toho v budocnu dočkáme :-)
Metodu seek(pocet)
je možno použít s
jedním argumentem – potom se implicitně předpokládá posun od začátku souboru.
>>> f.write(b'0123456789abcdef')
16
>>> f.seek(5) # Jdi na šestý bajt v souboru (první je 0)
5
>>> f.read(1)
b'5'
>>> f.seek(-3, 2) # jdi na třetí bajt od konce
13
>>> f.tell()
13
>>> f.read(1)
b'd'
>>> f.tell()
14
b
před řetězcem znamená, že se jedná o binární data.
Modul pickle
Modul pickle
umožňuje uložit do souboru objekty Pythonu a pak je
zase načíst. Můžete tak uložit celé seznamy, nebo vlastní třídy,
funkce …
>>> def funkce():
print("Hello World")
>>> seznam = ['ahoj', 3, funkce]
>>> # uložím seznam do souboru do dump.py
>>> pickle.dump(seznam, open("dump.py", "w"))
>>> # a zase si ho načtu
>>> x = pickle.load(open("dump.py", "r"))
>>> x[2]()
Hello World
Podívejte se do souboru dump.py. Všiměte si, jak je tam zapsána
funkce – jenom jako odkaz od jmenného prostoru. To má za následek,
že pokud Python ukončíte a pokusíte se dump znovu načíst, kvůli neexistenci
funkce funkce() se to nepodaří.
Pokud si funkci funkce() definujete, načtení z dump.py se
povede, ačkoliv definovaná funkce funkce() může být definovaná
úplně jinak než ta, kterou jste se pokusili uložit!
Další detaily se můžete dočíst v dokumentaci.
Moduly os a os.path
V těchto modulech najdete spoustu funkcí na práci se souborovým systémem.
>>> dir(os.path)
['__all__', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '_joinrealpath', '_unicode', '_uvarprog', '_varprog', 'abspath',
'altsep', 'basename', 'commonprefix', 'curdir', 'defpath', 'devnull', 'dirname', 'exists', 'expanduser', 'expandvars', 'extsep', 'genericpath',
'getatime', 'getctime', 'getmtime', 'getsize', 'isabs', 'isdir', 'isfile', 'islink', 'ismount', 'join', 'lexists', 'normcase', 'normpath',
'os', 'pardir', 'pathsep', 'realpath', 'relpath', 'samefile', 'sameopenfile', 'samestat', 'sep', 'split', 'splitdrive', 'splitext', 'stat',
'supports_unicode_filenames', 'sys', 'walk', 'warnings']
>>> help(os.path.isdir)
Help on function isdir in module genericpath:
isdir(s)
Return true if the pathname refers to an existing directory.
>>> os.path.isdir('/tmp/')
True
>>> from os.path import isdir
>>> isdir('/tmp/')
True
>>> os.listdir('/')
['boot', 'home', 'opt', 'srv', 'tmp', 'usr', 'var', 'etc', 'dev', 'proc', 'sys', 'run', 'bin', 'lib', 'lib64', 'root', 'sbin', 'mnt', 'selinux', '.snapshots', 'media', '.readahead']
Modul pathlib
Modul pathlib
je novým modulem pro práci s cestami v souborovém systému (od verze Python 3.4). Je zaměřen na zjednodušení
práce s různými souborovými systémy (Windows vs Linux). Zatím je v „provizorním„ stádiu vývoje, což znamená,
že se mohou v nových verzích vyskytnout nekompatibilní změny (funkce se budou chovat jinak). Takže, pokud budete
chtít tento modul používat, tak opatrně.
>>> p = Path('/')
>>> p.is_dir()
True
>>> list(p.glob('*u*'))
[PosixPath('/usr'), PosixPath('/run'), PosixPath('/selinux')]
>>> p = p / 'home' / 'petr'
>>> p
PosixPath('/home/petr')