<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xml" href="/cjs/screen.xsl" media="screen"?>
<lecture>

<meta>
  <maintitle>Python</maintitle>
  <author>Jiří Znamenáček</author>
  <title>Modul „tempfile“</title>
  <date>2012-xx-xx</date>
  <link><!--a href="http://vyuka.ookami.cz" rel="external">http://vyuka.ookami.cz</a--></link>
</meta>
<!--
  „“–…
  ←→ ↑↓ ↔↕
  ↵ aneb &#x21B5; aneb \r aneb CR aneb CarriageReturn
-->


<slide title="Úvod">

  <p>
    Často potřebujete ve svém programu někam odložit dočasná pracovní data. Existují standardní místa, která byste měli zkusit použít (např. <em>C:\TEMP</em> nebo <em>/tmp</em>) a která jsou k tomu např. svými právy pro zápis uzpůsobena.
  </p>
  <p>
    Starat se o to všechno ale sám a navíc tak, aby to fungovalo na libovolné cílové platformě, je dosti otrava a navíc další bezvadné místo na zanešení chyb (a to nejen bezpečnostních). Python právě pro tyto potřeby obsahuje velmi univerzální modul <code>tempfile</code>.
  </p>

</slide>
<slide title="Práce s dočasnými objekty">

  <p>
    Z pohledu uživatele se s <em>dočasnými objekty</em> (týká se to jak souborů, tak adresářů) pracuje téměř úplně stejně jako s normálními soubory a adresáři. Především to znamená, že výstupy příslušných konstruktorů můžete použít například v kontextu <code>with</code>:
  </p>
  <example lang="python">
    with tempfile.TemporaryFile() as fp:
        BLOK
  </example>
  <p>
    Snad jediným – zato ale důležitým – rozdílem je, že z důvodů co největší platformní nezávislosti jsou <em>dočasné soubory</em> ve výchozím nastavení otevírány zásadně jako <em>binární</em> (tedy v módu <code>b</code>).
  </p>
  <note>
    Výchozí mód otevření souborů je <code>w+b</code>, tedy binární otevřené pro čtení i zápis, přičemž případný již existující neprázdný soubor je při otevření nejdříve smazán.
  </note>

</slide>
<slide title="Umístění dočasných souborů">

  <p>
    Ačkoli většině funkcí modulu <em>tempfile</em> můžete vnutit vlastní umístění dočasných souborů, opravdu to není dobrý nápad, pokud pro to nemáte skutečně dobrý důvod.
  </p>
  <p>
    Python sám bude hledat vhodné místo podle následujícího algoritmu:
  </p>
  <ol>
    <li>
        Adresář uložený v proměnné prostředí <code>TMPDIR</code>.
    </li>
    <li>
        Adresář uložený v proměnné prostředí <code>TEMP</code>.
    </li>
    <li>
        Adresář uložený v proměnné prostředí <code>TMP</code>.
    </li>
    <li>
        Platformně závislé umístění:
        <ul>
            <li>
                <em>Windows</em>: postupně adresáře <code>C:\TEMP</code>, <code>C:\TMP</code>, <code>\TEMP</code> a <code>\TMP</code>
            </li>
            <li>
                <em>všude jinde</em>: postupně adresáře <code>/tmp</code>, <code>/var/tmp</code> a <code>/usr/tmp</code>
            </li>
        </ul>
    </li>
    <li>
        Jako místo poslední záchrany se Python pokusí použít aktuální pracovní adresář (tedy typicky místo spuštění programu).
    </li>
  </ol>

</slide>
<slide title="„TemporaryFile“">

  <p>
    Ačkoli plný konstruktor <code>TemporaryFile</code> pro tvorbu <strong>dočasných nepojmenovaných souborů</strong>, které jsou před každým pokud možno schovány (tím je myšleno, že jejich jméno není dostupné v programu a podporuje-li to platforma, tak ani v ní), je dosti šílený..
  </p>
  <example lang="python">
    tempfile.TemporaryFile(mode='w+b', buffering=None, encoding=None,
                           newline=None, suffix='', prefix='tmp', dir=None)
  </example>
  <p>
    ..pro běžné použití vzhledem k rozumnému výchozímu nastavení jednotlivých atributů není většinou potřeba používat složitější konstrukci než tuto:
  </p>
  <example lang="python">
    with tempfile.TemporaryFile() as fp:
        BLOK
  </example>
  <p>
    Z hlediska snad všech standardních operací se s výstupním objektem <em>fp</em> zachází stejně jako s každým běžným souborem.
  </p>

</slide>
<slide title="„NamedTemporaryFile“">

  <p>
    Konstruktor <code>NamedTemporaryFile</code> pro tvorbu <strong>dočasných pojmenovaných souborů</strong> je podobně šílený..
  </p>
  <example lang="python">
    tempfile.NamedTemporaryFile(mode='w+b', buffering=None, encoding=None,
                                newline=None, suffix='', prefix='tmp', dir=None,
                                delete=True)
  </example>
  <p>
    ..ale opět se s ním pracuje stejně jako s normálním souborem. Oproti <em>TemporaryFile</em> je tu však samozřejmě několik rozdílů:
  </p>
  <ul>
    <li>
        Vytvořený objekt má viditelné jméno. Je přístupné pod parametrem <em>file</em> na otevřeném proudu (<em>stream</em>u).
    </li>
    <li>
        Změnou parametru <em>delete</em> můžete určit, zda se dočasný soubor po ukončení práce s ním má ihned smazat (výchozí nastavení) nebo ne.
    </li>
  </ul>

</slide>
<slide title="„SpooledTemporaryFile“">

  <p>
    Třetí možností, jak zavést dočasný soubor, je konstruktor <code>SpooledTemporaryFile</code>. Na první pohled vypadá ještě šíleněji než oba předchozí..
  </p>
  <example lang="python">
    tempfile.SpooledTemporaryFile(max_size=0, mode='w+b', buffering=None,
                                  encoding=None, newline=None, suffix='',
                                  prefix='tmp', dir=None)
  </example>
  <p>
    ..ale ve skutečnosti je jen logickým završením řady dočasných souborů – dočasný soubor v jeho provedení je možno (za jistých podmínek) držet převážně pouze v paměti a fyzicky ho ukládat na disk až na vyžádání. Soubor přitom bude uložen z paměti na disk, pokud:
  </p>
  <ul>
    <li>
        Jeho velikost překročí hodnotu paramatru <em>max_size</em>.
    </li>
    <li>
        Na otevřeném proudu (<em>stream</em>u) je zavolána metoda <code>fileno()</code> (sloužící ke zjištění popisovače souboru).
    </li>
    <li>
        Je vynuceno jeho uložení na disk zavoláním metody <code>rollover()</code> (na otevřeném proudu).
    </li>
  </ul>

</slide>
<slide title="„TemporaryDirectory“">

  <p>
    Posledním z objektů je <code>TemporaryDirectory</code> sloužící pro správu dočasných adresářů:
  </p>
  <example lang="python">
    tempfile.TemporaryDirectory(suffix='', prefix='tmp', dir=None)
  </example>
  <p>
    Návratový objekt může být (stejně jako všechny předchozí) přímo použit v kontextu <em>with</em>. Po jeho opuštění je obsah dočasného adresáře, jakož i adresář sám, smazán ze souborového systému. Přitom:
  </p>
  <ul>
    <li>
        Jméno adresáře je uloženo v atributu <em>name</em> vráceného objektu.
    </li>
    <li>
        Dočasný adresář můžete úmyslně promazat zavoláním jeho metody <code>cleanup()</code>.
    </li>
  </ul>
  <p>
    Do takto vyvořeného adresáře můžete pak sázet soubory (nebo i adresáře) třebas i běžnými souborovými metodami – dočasný adresář je zlikviduje při svém uzavření (tedy odchodu z kontextu <em>with</em> nebo po ukončení skriptu).
  </p>
  <note>
    Výhodné, potřebujete-li vytvářet soubory sice dočasné, ale konkrétního jména.
  </note>

</slide>
<slide title="Ukázka">

  <example lang="python">
>>> import tempfile

# A) create a temporary file and write some data to it
>>> fp = tempfile.TemporaryFile()
>>> fp.write(b'Hello world!')
# read data from file
>>> fp.seek(0)
>>> fp.read()
b'Hello world!'
# close the file, it will be removed
>>> fp.close()

# B) create a temporary file using a context manager
>>> with tempfile.TemporaryFile() as fp:
...     fp.write(b'Hello world!')
...     fp.seek(0)
...     fp.read()
b'Hello world!'
>>>
# file is now closed and removed

# C) create a temporary directory using the context manager
>>> with tempfile.TemporaryDirectory() as tmpdirname:
...     print('created temporary directory', tmpdirname)
>>>
# directory and contents have been removed
  </example>
  <note>
    Velmi mírně upraveno podle dokumentace.
  </note>

</slide>


</lecture>
