V dnešním díle se podíváme na to, jaké možnosti běžného (terminál, soubory) vstupu a výstupu nám Python nabízí.
  
		2.3.2005 15:00 | Aleš Hakl | czytane 27681×
   
   
      	RELATED ARTICLES
      
	  KOMENTARZE   
      Již v předchozích dílech jsme zmínili příkaz print 
      pro vypisování dat na standardní výstup, toto samozřejmě není 
      jediná možnost  výstupu. Podobně jsme též zmínili funkci
      raw_input načítající řádek od uživatele, také to 
      samozřejmě není jediný prostředek vstupu dat, ačkoli pro jednoduché 
      načítání řetězců od uživatele je tato funkce jistě jednou z 
      nejvhodnějších.
    
    
      Nezmínili jsme funkci input, jež je stejná jako  funkce
      raw_input, navíc ovšem řetězec zadaný uživatelem vyhodnotí,
      jako kdyby byl výrazem v programu a vrátí výslednou hodnotu, v praxi
      se tato funkce v Pytonu ovšem příliš často nepoužívá.
    
    
      Python, podobně jako unix obecně, celkem nerozlišuje, z čeho čteme a 
      kam píšeme, pro programátora mezi souborem, terminálem či třeba 
      síťovým spojením není velký rozdíl, všechny tyto případy jsou 
      reprezentovány objektem s přibližně stejnými metodami, nazývejme 
      takový objekt stream (proud). 
      Samozřejmě stream implementuje pouze metody, 
      které pro něj mají smysl. Například čtení ze standardního výstupu 
      (většinou) smysl nemá.
    
    Standardní vstup a výstup
    
      Zpočátku můžeme za zajímavé považovat streamy reprezentující standardní 
      vstup, výstup a chybový výstup. Tyto proudy nalezneme ve standardním 
      modulu sys jako proměnné stdin, 
      stdout a stderr.
    
    
      Samozřejmě, že tyto proudy jsou proměnné jako každé jiné a je tedy 
      možné změnit stream používaný pro vstup či výstup a tím dosáhnout 
      nejrůznějších žádoucích efektů.
    
    Soubory
    
      Streamy také můžeme použít k přístupu k souborům, slouží k tomu 
      funkce open, která je přímo součástí interpretu jazyka 
      Python. Tato funkce má dva argumenty, jméno souboru a režim, ve kterém 
      bude otevřen. 
    
    
      Režim je řetězec, jehož první znak určuje jestli soubor chceme
      číst ('r'), přepsat ('w') nebo zapisovat 
      na jeho konec ('a').
      Dále můžeme uvést znak '+' pro zápis i čtení zároveň, 
      'r+' nám tedy
      umožní soubor jak číst tak zapisovat a 'w+' totéž, s 
      tím že bude 
      nejdříve smazán původní obsah souboru. Méně vyspělé operační systémy
      též mohou vyžadovat znak 'b' indikující binární soubor, 
      ten se zapisuje
      na druou pozici, za jeden ze znaků 'rwa'.
    
    
      Pokud režim neuvedeme použije se výchozí hodnota 'r'.
    
    Čtení ze streamu
    
      - read(počet bytů)- Přečte ze souboru daný 
      počet bytů a vrátí je jako řetězec, pokud počet bytů nezadáme, přečte 
      celý soubor. Je doufám zřejmé, že číst celý soubor najednou většinou
      není nejlepší řešení. Pokud funkce vrátí méně než udaný počet,
      dospěli jsme na konec souboru.
- readline(počet byte)- Přečte řádku,
      maximálně však daný počet bytů, opět parametr nemusíme udat
      a metoda přečte řádku celou, libovoně dlouhou.
- readlines()- Vrátí obsah souboru jako seznam řádek
- xreadlines()- Vrátí objekt, který můžeme
      použít například v cyklu- forpro zpracování
      všech řádek souboru, narozdíl od předchozí metody nenačítá celý soubor 
      najednou, ale po částech, tak jak jsou potřeba další data.
      Pokud tedy chceme přečíst soubor po jednotlivých řádcích a něco s
      nimi provést (což je dle mého názoru asi nejčastější operace, kterou 
      chceme v unixu se souborem provádět), uděláme to například takto:
    
    f = open('/etc/inittab','r')
i = 0 
for l in f.xreadlines():
    i = i + 1
    print i,l.rstrip()   # ořízneme bíle znaky na konci řádku
                         # (tj. minimálně znak nového řádku)
                         # a řádek očíslujeme.
Zápis do proudu
    
      - 
        write(řetězec)- zapíše řetězec do souboru,
	v podstatě tak jak leží a běží.
- 
        writelines(seznam)- zapíše do souboru všechny 
	řetězce v daném seznamu oddělené novým řádkem. Funguje to s ledasčím, 
	co vzdáleně připomíná seznam, soubor tedy můžeme na obrazovku vypsat 
	například takto:import sys
sys.stdout.writelines(open('/etc/inittab','r').xreadlines())
      Přesnou kopii souboru můžeme s využtím výše uvedených metod vytvořit 
      nějak takto:
    
    src = open('10.html','r')  # zdrojový soubor
dst = open('foo','w')      # cílový soubor
while True:
    buf = src.read(4096)   # čteme 4KiB najednou
    dst.write(buf)
    if len(buf) < 4096:
        breakPosun ve streamu
    
      Aktuální pozici ve streamu můžeme, pokud to daný stream podporuje,
      měnit. Je zřejmé, že je nesmysl pokoušet se měnit pozici ve streamu
      reprezentujícím nějaké zařízení nebo síťové spojení, cestovat časem
      Python opravdu neumí ^_^.
    
    
      - 
        tell()- vrátí aktuální pozici v souboru.
- 
        seek(offset, odkud)- nastaví
	novou pozici na offset od začátku souboru. Pokud uvedeme
	nepovinný parametr odkud počítá se nová pozice od začátku
	souboru (odkud = 0), aktuální pozice (1) nebo konce souboru
	(2). Zápis za konec souboru soubor automaticky zvětší.
- 
        truncate(délka) - zkrátí soubor na délka bytů,
	pokud parametr neuvedeme, zkrátí soubor na 0 bytů.
      
Ostatní metody
    
      - close()- uzavře soubor. Je vhodné tuto metodu zavolat
      pokud již se souborem nechceme dále pracovat.
- fileno()- vrátí číslo (deskriptor) souboru používaný
      při komunikaci s operačním systémem.
- flush()- Předá operačnímu systému dosud nezapsaná
      data. Tuto metodu je velmi vhodné zavolat u souborů otevřených pro čtení
      i zápis před čtení následujícím po zápisu.
- isatty()- Vrátí- Truepokud stream
      reprezentuje terminál.
Atributy
    
      Streamy také disponují několika atributy. Atribut closed
      má hodnotu True, pokud je stream uzavřen, name
      obsahuje jméno souboru nebo případně nějaký popis streamu, 
      mode obsahuje řetězec určující režim (druhý parametr 
      funkce open).
    
    
      Stream ovšem nemusí vůbec být soubor (nebo něco, co se z pohledu rozhraní
      operačního systému chová jako soubor), ale může to být téměř libovolná 
      třída. Ve standardní knihovně Pythonu tudíž nalezneme nejrůznější třídy
      různým způsobem obalující jiné streamy (například provádějící 
      komprimaci, převod kódování...) či jenom prostě implementující
      rozhraní streamu, protože autoři předpokládali, že je vhodné, aby
      daná třída vypadala jako stream.
    
    
      Dnešní díl tedy zakončíme souhrnnou ukázkou. Napíšeme program, který
      nám umožní na základě jednoho textového souboru zkopírovat konkrétní
      byte z jednoho souboru do druhého (k čemu to může být dobré, nechám na 
      představivosti čtenáře).
    
    
      Vstupem bude textový soubor se seznamem offsetů, vstupní binární soubor
      a výstupem bude jeden soubor obsahující dané byty.
    
    #!/usr/bin/env python
# -*- coding: utf-8; -*-
import sys
src_name = raw_input("Jméno vstupního souboru?")
txt_name = raw_input("Jméno souboru se seznamem offsetů?")
dst_name = raw_input("Jméno výstupního souboru?")
txt = open(txt_name,'r')
src = open(src_name,'rb') 
dst = open(dst_name,'wb')
for off_s in txt.xreadlines():
    off = long(off_s)  # Převedeme na číslo
    src.seek(off)      # nastavíme pozici
    byte = src.read(1) # přečteme 1 byte
    if byte=='':       # případně upozorníme uživatele na možnou chybu
        sys.stderr.write("Offset za koncem vstupního souboru")
    dst.write(byte)
# uklidíme po sobě
src.close() 
dst.close() 
txt.close()
         Doufám, že vás dnešní poněkud vykonstruovaná ukázka neodradila
	 a sejdeme se u dalšího dílu, tentokrát se podíváme na řetězce 
	 poněkud podrobněji.