Dnes se podíváme na to, jak v Pythonu číst z (a pak i zapisovat do) souborů.
Vytvoř si v editoru soubor basnicka.txt
a napiš do něj libovolnou básničku.
Soubor ulož.
Na uložení souboru s básničkou doporučuji použít stejný editor, jaký používáš na Pythonní programy.
Používáš-li jiný editor než Atom, dej si při ukládání pozor na kódování:
'utf-8'
nestandardní 'utf-8-sig'
.Ono utf-8
je název standardního kódování.
Zajišťuje, že se případné emoji nebo znaky s diakritikou do souboru uloží
tak, aby se daly přečíst i na jiném počítači či operačním systému.
🎉
Potom napiš tento program:
soubor = open('basnicka.txt', encoding='utf-8')
obsah = soubor.read()
soubor.close()
print(obsah)
a spusť ho z adresáře, ve kterém je
basnicka.txt
(jinými slovy, aktuální adresář musí být ten, který
obsahuje soubor s básničkou).
Obsah souboru se vypíše!
Co se tu děje?
Tak jako int()
vrací čísla a input()
řetězce, funkce
open()
vrací hodnotu, která představuje otevřený soubor.
Tahle hodnota má vlastní metody.
Tady používáme metodu read()
, která
najednou přečte celý obsah souboru a vrátí ho jako řetězec.
Nakonec metoda close()
otevřený soubor zase zavře.
Soubory se dají přirovnat k ledničce: abys něco mohla z ledničky vzít, nebo dát dovnitř, musíš ji předtím otevřít a potom zavřít. Bez zavření to sice na první pohled funguje taky, ale pravděpodobně potom brzo něco zplesniví.
Stejně tak je docela důležité soubor zavřít po tom, co s ním přestaneš pracovat. Bez zavření to na první pohled funguje, ale složitější programy se můžou dostat do problémů. Operační systémy mají limity na počet současně otevřených souborů, které se nezavíráním dají snadno překročit. Na Windows navíc nemůžeš soubor, který je stále otevřený, otevřít znovu.
Na korektní zavření souboru ale programátoři často zapomenou.
Proto Python poskytuje příkaz with
, který soubory zavírá automaticky.
Používá se takhle:
with open('basnicka.txt', encoding='utf-8') as soubor:
obsah = soubor.read()
print(obsah)
Příkaz with
vezme otevřený soubor (který vrací funkce open
)
a přiřadí ho do proměnné soubor
.
Pak následuje odsazený blok kódu, kde se souborem můžeš pracovat – v tomhle
případě pomocí metody read
přečíst obsah jako řetězec.
Když se Python dostane na konec odsazeného bloku, soubor automaticky zavře.
V naprosté většině případů je pro otevírání souborů nejlepší použít with
.
Otevřené soubory se, jako např. řetězce či range
,
dají použít s příkazem for
.
Tak jako for i in range
poskytuje za sebou jdoucí čísla a for znak in 'abcd'
poskytuje jednotlivé znaky řetězce, for radek in soubor
bude v proměnné
radek
poskytovat jednotlivé řádky čtené ze souboru.
Aby se básnička líp vyjímala v textu, pojďme ji odsadit – před každý řádek dát měkolik mezer:
print('Slyšela jsem tuto básničku:')
print()
with open('basnicka.txt', encoding='utf-8') as soubor:
for radek in soubor:
print(' ' + radek)
print()
print('Jak se ti líbí?')
Když to zkusíš, zjistíš, že trochu nesedí řádkování. Zkusíš se zamyslet, proč tomu tak je?
Ideální způsob, jak odřádkování spravit, je odstranit z konce řetězce
bílé znaky (mezery a nové řádky) pomocí metody rstrip
:
print('Slyšela jsem tuto básničku:')
print()
with open('basnicka.txt', encoding='utf-8') as soubor:
for radek in soubor:
radek = radek.rstrip()
print(' ' + radek)
print()
print('Jak se ti líbí?')
Pozor!
Pro Python není problém smazat obsah jakéhokoli souboru. Psaní do souborů si zkoušej v adresáři, ve kterém nemáš uložené důležité informace!
Soubory se v Pythonu dají i zapisovat.
Pro zápis soubor otevři s pojmenovaným
argumentem mode='w'
(z angl. mode, mód a write, psát).
Pokud soubor už existuje, otevřením s mode='w'
se veškerý jeho obsah smaže.
Po zavření tak v souboru bude jen to, co do něj ve svém programu zapíšeš.
Informace pak do souboru zapiš známou funkcí print
,
ale s pojmenovaným argumentem file
:
with open('druha-basnicka.txt', mode='w', encoding='utf-8') as soubor:
print('Naše staré hodiny', file=soubor)
print('Bijí', 2+2, 'hodiny', file=soubor)
Čteš-li tyto materiály poprvé, tuto sekci můžeš s klidným svědomím přeskočit. Pokročilejším ale doporučuju vsadit věci do širšího kontextu.
Příkaz with
pracuje s tzv. kontextem (tady s kontextem otevřeného
souboru), který má začátek a konec a při ukončení je potřeba něco udělat
(tady zavřít soubor).
Kontext je v podstatě zkratka pro try
/finally
. Pamatuješ si na finally
?
Toto:
with open('basnicka.txt', encoding='utf-8') as soubor:
# Zpracování souboru
obsah = soubor.read()
je zkratka pro:
soubor = open('basnicka.txt', encoding='utf-8')
try:
# Zpracování souboru
obsah = soubor.read()
finally:
# Ukončení kontextu
soubor.close()
Jak with
tak finally
zaručí, že se soubor vždy uzavře:
když se zpracování povede, ale i když ve něm nastane výjimka
nebo když z něj vyzkočíš pomocí return
nebo break
.
{ "data": { "sessionMaterial": { "id": "session-material:2019/brno-podzim-pondeli:iterable:0", "title": "Soubory", "html": "\n \n \n\n <h1>Soubory</h1>\n<p>Dnes se podíváme na to, jak v Pythonu číst z\n(a pak i zapisovat do) souborů.</p>\n<p>Vytvoř si v editoru soubor <code>basnicka.txt</code> a napiš do něj libovolnou básničku.\nSoubor ulož.</p>\n<div class=\"admonition note\"><p>Na uložení souboru s básničkou doporučuji použít\nstejný editor, jaký používáš na Pythonní programy.</p>\n<p>Používáš-li jiný editor než Atom, dej si při ukládání pozor na kódování:</p>\n<ul>\n<li>Nabízí-li ti editor při ukládání výběr kódování, vyber UTF-8.</li>\n<li>Je-li k dispozici kódování „UTF-8 bez BOM”, použij to.</li>\n<li>Pokud musíš použít Notepad, který výše uvedené možnosti nemá, pak v kódu\nníže použij místo <code>'utf-8'</code> nestandardní <code>'utf-8-sig'</code>.</li>\n</ul>\n<p>Ono <a href=\"https://en.wikipedia.org/wiki/UTF-8\"><code>utf-8</code></a> je název standardního kódování.\nZajišťuje, že se případné emoji nebo znaky s diakritikou do souboru uloží\ntak, aby se daly přečíst i na jiném počítači či operačním systému.\n🎉</p>\n</div><p>Potom napiš tento program:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"n\">soubor</span> <span class=\"o\">=</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"s1\">'basnicka.txt'</span><span class=\"p\">,</span> <span class=\"n\">encoding</span><span class=\"o\">=</span><span class=\"s1\">'utf-8'</span><span class=\"p\">)</span>\n<span class=\"n\">obsah</span> <span class=\"o\">=</span> <span class=\"n\">soubor</span><span class=\"o\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n<span class=\"n\">soubor</span><span class=\"o\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">obsah</span><span class=\"p\">)</span>\n</pre></div><p>a spusť ho z adresáře, ve kterém je\n<code>basnicka.txt</code> (jinými slovy, aktuální adresář musí být ten, který\nobsahuje soubor s básničkou).</p>\n<p>Obsah souboru se vypíše!</p>\n<p>Co se tu děje?\nTak jako <code>int()</code> vrací čísla a <code>input()</code> řetězce, funkce\n<code>open()</code> vrací hodnotu, která představuje <em>otevřený soubor</em>.\nTahle hodnota má vlastní metody.\nTady používáme metodu <code>read()</code>, která\nnajednou přečte celý obsah souboru a vrátí ho jako řetězec.\nNakonec metoda <code>close()</code> otevřený soubor zase zavře.</p>\n<h2>Automatické zavírání souborů</h2>\n<p>Soubory se dají přirovnat k ledničce: abys něco\nmohla z ledničky vzít, nebo dát dovnitř, musíš\nji předtím otevřít a potom zavřít.\nBez zavření to sice na první pohled funguje taky,\nale pravděpodobně potom brzo něco zplesniví.</p>\n<p>Stejně tak je docela důležité soubor zavřít po tom,\nco s ním přestaneš pracovat.\nBez zavření to na první pohled funguje, ale složitější programy se můžou dostat\ndo problémů.\nOperační systémy mají limity na počet\nsoučasně otevřených souborů, které se nezavíráním\ndají snadno překročit.\nNa Windows navíc nemůžeš soubor, který je stále\notevřený, otevřít znovu.</p>\n<p>Na korektní zavření souboru ale programátoři často zapomenou.\nProto Python poskytuje příkaz <code>with</code>, který soubory zavírá automaticky.\nPoužívá se takhle:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"s1\">'basnicka.txt'</span><span class=\"p\">,</span> <span class=\"n\">encoding</span><span class=\"o\">=</span><span class=\"s1\">'utf-8'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">soubor</span><span class=\"p\">:</span>\n <span class=\"n\">obsah</span> <span class=\"o\">=</span> <span class=\"n\">soubor</span><span class=\"o\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">obsah</span><span class=\"p\">)</span>\n</pre></div><p>Příkaz <code>with</code> vezme otevřený soubor (který vrací funkce <code>open</code>)\na přiřadí ho do proměnné <code>soubor</code>.\nPak následuje odsazený blok kódu, kde se souborem můžeš pracovat – v tomhle\npřípadě pomocí metody <code>read</code> přečíst obsah jako řetězec.\nKdyž se Python dostane na konec odsazeného bloku, soubor automaticky zavře.</p>\n<p>V naprosté většině případů je pro otevírání souborů nejlepší použít <code>with</code>.</p>\n<h2>Iterace nad soubory</h2>\n<p>Otevřené soubory se, jako např. řetězce či <code>range</code>,\ndají použít s příkazem <code>for</code>.\nTak jako <code>for i in range</code> poskytuje za sebou jdoucí čísla a <code>for znak in 'abcd'</code>\nposkytuje jednotlivé znaky řetězce, <code>for radek in soubor</code> bude v proměnné\n<code>radek</code> poskytovat jednotlivé <em>řádky</em> čtené ze souboru.</p>\n<p>Aby se básnička líp vyjímala v textu, pojďme ji odsadit –\npřed každý řádek dát měkolik mezer:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s1\">'Slyšela jsem tuto básničku:'</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">()</span>\n\n<span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"s1\">'basnicka.txt'</span><span class=\"p\">,</span> <span class=\"n\">encoding</span><span class=\"o\">=</span><span class=\"s1\">'utf-8'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">soubor</span><span class=\"p\">:</span>\n <span class=\"k\">for</span> <span class=\"n\">radek</span> <span class=\"ow\">in</span> <span class=\"n\">soubor</span><span class=\"p\">:</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s1\">' '</span> <span class=\"o\">+</span> <span class=\"n\">radek</span><span class=\"p\">)</span>\n\n<span class=\"k\">print</span><span class=\"p\">()</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s1\">'Jak se ti líbí?'</span><span class=\"p\">)</span>\n</pre></div><p>Když to zkusíš, zjistíš, že trochu nesedí řádkování.\nZkusíš se zamyslet, proč tomu tak je?</p>\n<div class=\"solution\" id=\"solution-0\">\n <h3>Řešení</h3>\n <div class=\"solution-cover\">\n <a href=\"/2019/brno-podzim-pondeli/beginners/files/index/solutions/0/\"><span class=\"link-text\">Ukázat řešení</span></a>\n </div>\n <div class=\"solution-body\" aria-hidden=\"true\">\n <p>Každý řádek končí znakem nového řádku, <code>'\\n'</code>,\nkterý možná znáš ze <a href=\"/2019/brno-podzim-pondeli/beginners/str/\">sekce o řetězcích</a>.\nPři procházení souboru Python tento znak nechává na konci řetězce <code>radek</code> ¹.\nFunkce <code>print</code> pak přidá další nový řádek, protože ta na konci\nvýpisu vždycky odřádkovává – pokud nedostane argument <code>end=''</code>.</p>\n<hr>\n<p>¹ <em>Proč to dělá? Kdyby <code>'\\n'</code> na konci řádků nebylo,\nnedalo by se např. dobře rozlišit, jestli poslední řádek\nkončí na <code>'\\n'</code>.</em></p>\n </div>\n</div><p>Ideální způsob, jak odřádkování spravit, je odstranit z konce řetězce\nbílé znaky (mezery a nové řádky) pomocí metody <code>rstrip</code>:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s1\">'Slyšela jsem tuto básničku:'</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">()</span>\n\n<span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"s1\">'basnicka.txt'</span><span class=\"p\">,</span> <span class=\"n\">encoding</span><span class=\"o\">=</span><span class=\"s1\">'utf-8'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">soubor</span><span class=\"p\">:</span>\n <span class=\"k\">for</span> <span class=\"n\">radek</span> <span class=\"ow\">in</span> <span class=\"n\">soubor</span><span class=\"p\">:</span>\n <span class=\"n\">radek</span> <span class=\"o\">=</span> <span class=\"n\">radek</span><span class=\"o\">.</span><span class=\"n\">rstrip</span><span class=\"p\">()</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s1\">' '</span> <span class=\"o\">+</span> <span class=\"n\">radek</span><span class=\"p\">)</span>\n\n<span class=\"k\">print</span><span class=\"p\">()</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s1\">'Jak se ti líbí?'</span><span class=\"p\">)</span>\n</pre></div><h2>Psaní souborů</h2>\n<div class=\"admonition warning\"><p class=\"admonition-title\">Pozor!</p>\n<p>Pro Python není problém smazat obsah jakéhokoli souboru.\nPsaní do souborů si zkoušej v adresáři, ve kterém nemáš uložené\ndůležité informace!</p>\n</div><p>Soubory se v Pythonu dají i zapisovat.\nPro zápis soubor otevři s pojmenovaným\nargumentem <code>mode='w'</code> (z angl. <em>mode</em>, mód a <em>write</em>, psát).</p>\n<p>Pokud soubor už existuje, otevřením s <code>mode='w'</code> se veškerý jeho obsah smaže.\nPo zavření tak v souboru bude jen to, co do něj ve svém programu zapíšeš.</p>\n<p>Informace pak do souboru zapiš známou funkcí <code>print</code>,\nale s pojmenovaným argumentem <code>file</code>:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"s1\">'druha-basnicka.txt'</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s1\">'w'</span><span class=\"p\">,</span> <span class=\"n\">encoding</span><span class=\"o\">=</span><span class=\"s1\">'utf-8'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">soubor</span><span class=\"p\">:</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s1\">'Naše staré hodiny'</span><span class=\"p\">,</span> <span class=\"nb\">file</span><span class=\"o\">=</span><span class=\"n\">soubor</span><span class=\"p\">)</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s1\">'Bijí'</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"o\">+</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"s1\">'hodiny'</span><span class=\"p\">,</span> <span class=\"nb\">file</span><span class=\"o\">=</span><span class=\"n\">soubor</span><span class=\"p\">)</span>\n</pre></div><h2>Kontext</h2>\n<div class=\"admonition note\"><p>Čteš-li tyto materiály poprvé, tuto sekci můžeš s klidným svědomím přeskočit.\nPokročilejším ale doporučuju vsadit věci do širšího kontextu.</p>\n</div><p>Příkaz <code>with</code> pracuje s tzv. <em>kontextem</em> (tady s kontextem <em>otevřeného\nsouboru</em>), který má začátek a konec a při ukončení je potřeba něco udělat\n(tady zavřít soubor).</p>\n<p>Kontext je v podstatě zkratka pro <code>try</code>/<code>finally</code>. Pamatuješ si na <code>finally</code>?</p>\n<p>Toto:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"s1\">'basnicka.txt'</span><span class=\"p\">,</span> <span class=\"n\">encoding</span><span class=\"o\">=</span><span class=\"s1\">'utf-8'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">soubor</span><span class=\"p\">:</span>\n <span class=\"c1\"># Zpracování souboru</span>\n <span class=\"n\">obsah</span> <span class=\"o\">=</span> <span class=\"n\">soubor</span><span class=\"o\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n</pre></div><p>je zkratka pro:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"n\">soubor</span> <span class=\"o\">=</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"s1\">'basnicka.txt'</span><span class=\"p\">,</span> <span class=\"n\">encoding</span><span class=\"o\">=</span><span class=\"s1\">'utf-8'</span><span class=\"p\">)</span>\n<span class=\"k\">try</span><span class=\"p\">:</span>\n <span class=\"c1\"># Zpracování souboru</span>\n <span class=\"n\">obsah</span> <span class=\"o\">=</span> <span class=\"n\">soubor</span><span class=\"o\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n<span class=\"k\">finally</span><span class=\"p\">:</span>\n <span class=\"c1\"># Ukončení kontextu</span>\n <span class=\"n\">soubor</span><span class=\"o\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n</pre></div><p>Jak <code>with</code> tak <code>finally</code> zaručí, že se soubor vždy uzavře:\nkdyž se zpracování povede, ale i když ve něm nastane výjimka\nnebo když z něj vyzkočíš pomocí <code>return</code> nebo <code>break</code>.</p>\n\n\n " } } }