Java: Textový vstup a výstup
| m (Do přehledu metod Scanneru přidáno nextLine() a hasNextLine()) |  (Opraveno na použití try-with-resources.) | ||
| (Nejsou zobrazeny 3 mezilehlé verze od 1 uživatele.) | |||
| Řádka 6: | Řádka 6: | ||
| * Více o výjimkách si přečtete zde: [[Výjimky v Javě]]. | * Více o výjimkách si přečtete zde: [[Výjimky v Javě]]. | ||
| * Pro tuto chvíli bude stačit, když víte, že práci se soubory je vždy potřeba obklopit kódem pro řešení chyb: | * Pro tuto chvíli bude stačit, když víte, že práci se soubory je vždy potřeba obklopit kódem pro řešení chyb: | ||
| − |   try { ''//  | + |   try (''otevření souboru'') { ''// Otevři soubor a začni tím blok, ve kterém může nastat chybový stav...'' | 
|       ''... zde následuje kód, pracující se souborem...'' |       ''... zde následuje kód, pracující se souborem...'' | ||
|   } catch (IOException ex) {   |   } catch (IOException ex) {   | ||
| Řádka 14: | Řádka 14: | ||
|   }   |   }   | ||
| * Více viz [[Výjimky v Javě]]. | * Více viz [[Výjimky v Javě]]. | ||
| − | |||
| == Čtení ze souboru (<code>Scanner</code>) == | == Čtení ze souboru (<code>Scanner</code>) == | ||
| Řádka 21: | Řádka 20: | ||
| * Pro čtení dat z textových souborů slouží v Javě třída <code>Scanner</code> z balíčku <code>java.util</code>. | * Pro čtení dat z textových souborů slouží v Javě třída <code>Scanner</code> z balíčku <code>java.util</code>. | ||
| * Slouží také pro čtení vstupu z klávesnice v konzolových aplikacích (aplikacích, které běží jen v příkazovém řádku). | * Slouží také pro čtení vstupu z klávesnice v konzolových aplikacích (aplikacích, které běží jen v příkazovém řádku). | ||
| − | * Zaveden od Javy 5 —  | + | * Zaveden od Javy 5 — lze použít pro převod hodnot z textového zápisu jako „zapouzdření“ třídy <tt>BufferedReader</tt>. | 
| * Výhodou je, že umí automaticky načíst čísla (včetně desetinných) z jejich textové podoby. | * Výhodou je, že umí automaticky načíst čísla (včetně desetinných) z jejich textové podoby. | ||
| Řádka 31: | Řádka 30: | ||
| ; Konstruktory třídy <code>Scanner</code>: | ; Konstruktory třídy <code>Scanner</code>: | ||
| + | * <code>Scanner(BufferedReader otevrenyVstupniStream, String encoding)</code> | ||
| * <code>Scanner(File vstupniSoubor, String encoding)</code> | * <code>Scanner(File vstupniSoubor, String encoding)</code> | ||
| * <code>Scanner(Path vstupniSoubor, String encoding)</code> | * <code>Scanner(Path vstupniSoubor, String encoding)</code> | ||
| Řádka 94: | Řádka 94: | ||
|   ''...'' |   ''...'' | ||
| − | + |   String nazev = "vstup.txt"; | |
| − | + |  Scanner sc = null; | |
| − | + |  try (Scanner sc = new Scanner(new BufferedReader(new File(nazev)), "windows-1250");) { | |
| − |       int cislo = sc.nextInt() | + |       int cislo = sc.nextInt(); | 
| − | + |       ''// ...'' | |
| − |   } catch (FileNotFoundException ex) { System.err.println("Nenalezen soubor: "+nazev+"!";  | + |   } catch (FileNotFoundException ex) { System.err.println("Nenalezen soubor: "+nazev+"!"); | 
| − |   } catch (IOException ex) { System.err.println("Chyba čtení ze souboru "+nazev+": "+ex.getLocalizedMessage());  | + |   } catch (IOException ex) { System.err.println("Chyba čtení ze souboru "+nazev+": "+ex.getLocalizedMessage()); | 
| − |   } catch (InputMismatchException ex) { System.err.println("Nesprávný formát dat v souboru "+nazev+": "+ex.getLocalizedMessage());  | + |   } catch (InputMismatchException ex) { System.err.println("Nesprávný formát dat v souboru "+nazev+": "+ex.getLocalizedMessage());   | 
| − | + |   } | |
| − | + | ||
| <div class="Poznamka"> | <div class="Poznamka"> | ||
| − | Pokud zadáte pouze název souboru,  | + | Pokud zadáte pouze název souboru, hledá se soubor v aktuální složce. Která složka je aktuální:   | 
| − | + | * Při spuštění z vývojového prostředí (Greenfoot, NetBeans,...) je to obvykle složka, ve které jsou umístěny zdrojové soubory (na stejné úrovni jako složka <tt>src</tt>). | |
| − | Která složka je aktuální:   | + | |
| − | * Při spuštění z vývojového prostředí (Greenfoot, NetBeans,...) je to obvykle složka, ve které jsou umístěny zdrojové soubory. | + | |
| * Při spuštění samostatného souboru .JAR je to složka, ve které je soubor .JAR umístěn. | * Při spuštění samostatného souboru .JAR je to složka, ve které je soubor .JAR umístěn. | ||
| − | Můžete zadat i celou cestu, například pro Windows: <code>String nazev = "C:\\temp\\data.txt";</code>. | + | Můžete zadat i celou cestu, například pro Windows: <code>String nazev = "C:\\temp\\data.txt";</code>, ale pak výsledný program funguje jen na vašem počítači a na počítačích, které mají soubor přesně ve stejném umístění. | 
| </div> | </div> | ||
| Řádka 122: | Řádka 119: | ||
|   ''...'' |   ''...'' | ||
| − | + |   String nazev = "vstup.txt"; | |
| − | + |  try (Scanner sc = new Scanner(new BufferedReader(new File(nazev))), "windows-1250"); | |
| − | + | ||
|       while (sc.hasNextInt()) { |       while (sc.hasNextInt()) { | ||
|           int cislo = sc.nextInt(); |           int cislo = sc.nextInt(); | ||
|           System.out.println(cislo); |           System.out.println(cislo); | ||
|       } |       } | ||
| − | + |   } catch (FileNotFoundException ex) { System.err.println("Nenalezen soubor: "+nazev+"!");   | |
| − |   } catch (FileNotFoundException ex) { System.err.println("Nenalezen soubor: "+nazev+"!";  | + |   } catch (IOException ex) { System.err.println("Chyba čtení ze souboru "+nazev+": "+ex.getLocalizedMessage());   | 
| − |   } catch (IOException ex) { System.err.println("Chyba čtení ze souboru "+nazev+": "+ex.getLocalizedMessage());  | + |   } catch (InputMismatchException ex) { System.err.println("Nesprávný formát dat v souboru "+nazev+": "+ex.getLocalizedMessage());   | 
| − |   } catch (InputMismatchException ex) { System.err.println("Nesprávný formát dat v souboru "+nazev+": "+ex.getLocalizedMessage()); }   | + |  } | 
|   ''...'' |   ''...'' | ||
| Řádka 150: | Řádka 146: | ||
|   Scanner sc = new Scanner(System.in); |   Scanner sc = new Scanner(System.in); | ||
|   int i = sc.nextInt(); |   int i = sc.nextInt(); | ||
| − | + |   String text = input.next(); | |
|   sc.close(); |   sc.close(); | ||
| Řádka 199: | Řádka 195: | ||
|   String kodovani = "windows-1250"; |   String kodovani = "windows-1250"; | ||
|   String nazevSouboru = "vystup.txt"; |   String nazevSouboru = "vystup.txt"; | ||
| − |   try  | + |   try (PrintWriter out = new PrintWriter(new File(nazevSouboru), kodovani)) | 
| − | + | ||
| − | + | ||
|       out.println("Hello world!"); |       out.println("Hello world!"); | ||
|       out.close(); |       out.close(); | ||
Aktuální verze z 7. 11. 2022, 10:07
| Obsah | 
Ošetření chyb, výjimky
- Při práci se souborem je třeba vždy počítat s tím, že může nastat chyba (soubor je poškozený, soubor někdo smazal,...).
- Java používá pro ošetření chybových stavů mechanismus výjimek (exception).
- Více o výjimkách si přečtete zde: Výjimky v Javě.
- Pro tuto chvíli bude stačit, když víte, že práci se soubory je vždy potřeba obklopit kódem pro řešení chyb:
try (otevření souboru) { // Otevři soubor a začni tím blok, ve kterém může nastat chybový stav...
    ... zde následuje kód, pracující se souborem...
} catch (IOException ex) { 
    // Co se má stát, pokud nastane chyba při práci se souborem...
} catch (FileNotFoundException ex) { 
    // Co se má stát, když zadaný soubor vůbec neexistuje
} 
- Více viz Výjimky v Javě.
  Čtení ze souboru (Scanner) 
  Třída Scanner 
-  Pro čtení dat z textových souborů slouží v Javě třída Scannerz balíčkujava.util.
- Slouží také pro čtení vstupu z klávesnice v konzolových aplikacích (aplikacích, které běží jen v příkazovém řádku).
- Zaveden od Javy 5 — lze použít pro převod hodnot z textového zápisu jako „zapouzdření“ třídy BufferedReader.
- Výhodou je, že umí automaticky načíst čísla (včetně desetinných) z jejich textové podoby.
Otevření souboru
-  Soubor otevřeme pro čtení tak, že vytvoříme novou instanci třídy Scannera jako parametr konstruktoru předáme soubor, kterých chceme otevřít.
-  Jako druhý parametr konstruktoru můžeme předat také kódování znaků, které jsme při vytváření souborů použili. Pokud soubor vytváříte v Poznámkovém bloku Windows, použijte kódování Windows-1250.
-  Konstruktory třídy Scanner
-  Scanner(BufferedReader otevrenyVstupniStream, String encoding)
-  Scanner(File vstupniSoubor, String encoding)
-  Scanner(Path vstupniSoubor, String encoding)
- ...
Kódování národních znaků:
- U všech konstruktorů můžeme druhý parametr vynechat, pak se použije kódování UTF-8.
-  Označení běžných kódování, používaných pro češtinu: 
-  windows-1250... programy ve Windows (Poznámkový blok, Excel,...),
-  cp852... skripty pro příkazový řádek,
-  uft-8... programátorské nástroje, programy v Linuxu.
 
-  
Pokud nenastavíte správné kódování českých znaků, třída Scanner se při ladění v prostředí NetBeans 8.0.2 (JDK 7u71) může chovat k souboru, jako by byl prázdný.
Pokud máte podobné problémy, zkuste:
a) nastavte správné kódování češtiny v konstruktoru Scanneru či zkonvertujte soubor na správné kódování (třeba pomocí Notepadu++ či jiného editoru, který umí nastavit kódování).
b) projekt přeložte (Clean & Build) a spusťte přímo výsledný JAR ze složky dist v adresáři projektu. (viz Export balíčku JAR).
  Metody třídy Scanner 
- Získání dalšího bloku dat ze souboru
-  next()- přečte další položku souboru až po oddělovač (viz dále)
- při čtení z konzole (klávesnice) čeká na oddělovač
- bere jednotlivá slova, oddělená standardně bílým místem
 
-  int nextInt()
-  int nextDouble()- vrací objektový typ Double.
- Desetinná čísla je třeba zadávat podle národního nastavení. Pro české nastavení tedy s desetinnou čárkou.
 
-  String nextLine()- Načte jeden řádek textu až po konec řádku (neřeší nastavení oddělovače/delimiteru).
 
- Zjištění — je v souboru další blok dat?
-  boolean hasNext()- je k dispozici další slovo?
 
-  boolean hasNextInt()- následuje na vstupu celé číslo?
 
-  boolean hasNextDouble()- následuje na vstupu desetinné číslo?
 
-  boolean hasNextLine()- je na vstupu další celý řádek?
 
- Další nastavení
-  useDelimiter(String delim), resp.useDelimiter(Pattern delim)-  Oddělovač položek na řádku, například:out.useDelimiter(",");
-  Jako oddělovač lze použít i regulární výraz (→ Wikipedia.org) reprezentovaný třídou Pattern.
- Pro načítání jednoduchého CSV lze použít (pozor, není to plnohodnotné čtení CSV, ale mnohdy stačí):
 
-  Oddělovač položek na řádku, například:
out.useDelimiter("\\s*[;,\n\r\t]\\s*")
- Ukončení práce se souborem
-  close()- Ukončení práce se souborem – uzavření souboru.
- Vždy bychom měli zavolat po dokončení čtení.
 
Příklad: Načtení jednoho čísla ze souboru
import java.util.Scanner;
import java.io.File;
...
String nazev = "vstup.txt";
Scanner sc = null;
try (Scanner sc = new Scanner(new BufferedReader(new File(nazev)), "windows-1250");) {
    int cislo = sc.nextInt();
    // ...
} catch (FileNotFoundException ex) { System.err.println("Nenalezen soubor: "+nazev+"!");
} catch (IOException ex) { System.err.println("Chyba čtení ze souboru "+nazev+": "+ex.getLocalizedMessage());
} catch (InputMismatchException ex) { System.err.println("Nesprávný formát dat v souboru "+nazev+": "+ex.getLocalizedMessage()); 
}
Pokud zadáte pouze název souboru, hledá se soubor v aktuální složce. Která složka je aktuální:
- Při spuštění z vývojového prostředí (Greenfoot, NetBeans,...) je to obvykle složka, ve které jsou umístěny zdrojové soubory (na stejné úrovni jako složka src).
- Při spuštění samostatného souboru .JAR je to složka, ve které je soubor .JAR umístěn.
Můžete zadat i celou cestu, například pro Windows: String nazev = "C:\\temp\\data.txt";, ale pak výsledný program funguje jen na vašem počítači a na počítačích, které mají soubor přesně ve stejném umístění.
Příklad: Načtení všech čísel ze souboru
import java.util.Scanner;
import java.io.File;
...
String nazev = "vstup.txt";
try (Scanner sc = new Scanner(new BufferedReader(new File(nazev))), "windows-1250");
    while (sc.hasNextInt()) {
        int cislo = sc.nextInt();
        System.out.println(cislo);
    }
} catch (FileNotFoundException ex) { System.err.println("Nenalezen soubor: "+nazev+"!"); 
} catch (IOException ex) { System.err.println("Chyba čtení ze souboru "+nazev+": "+ex.getLocalizedMessage()); 
} catch (InputMismatchException ex) { System.err.println("Nesprávný formát dat v souboru "+nazev+": "+ex.getLocalizedMessage()); 
}
...
Příklad: Načtení všech řádků textu ze souboru
Scanner sc = new Scanner(new File("myRows"), "windows-1250");
while (sc.hasNextLine()) {
    ...
    String radek = sc.nextLine();
    ...
}
sc.close();
Příklad: Načtení jednoho čísla z klávesnice
- Použijte pouze v aplikacích pro příkazový řádek (ne v Greenfootu nebo aplikacích s grafickým uživatelským prostředím).
Scanner sc = new Scanner(System.in); int i = sc.nextInt(); String text = input.next(); sc.close();
Zápis do souboru (PrintWriter)
Třída PrintWriter slouží pro zápis dat do textového výstupu.
- Využívá efektivnější zápis pomocí vyrovnávací paměti (bufferu)
- Ukládá zapisovaná data do paměťového bufferu.
- Teprve při dosažení limitu data naráz zapíše.
- Je to efektivnější, než zapisovat jednotlivé malé kousky textu hned!
- Otevření souboru
String kodovani = "windows-1250"; String nazev = "vystup.txt"; PrintWriter out = new PrintWriter(new File(nazev), kodovani);
Pokud zadáte pouze název souboru, hledá se soubor v aktuální složce.
Která složka je aktuální:
- Při spuštění z vývojového prostředí (Greenfoot, NetBeans,...) je to obvykle složka, ve které jsou umístěny zdrojové soubory.
- Při spuštění samostatného souboru .JAR je to složka, ve které je soubor .JAR umístěn.
Můžete zadat i celou cestu, například pro Windows: String nazev = "C:\\temp\\data.txt";.
- Metody
-  println(String text)- Přidá řádek do výstupního souboru.
 
-  flush()- Provede fyzický zápis stávajícího obsahu bufferu na výstup.
 
-  close()- Zavře výstupní soubor.
-  Provede i flush().
 
Příklad — Zápis věty do souboru
import java.io.File; import java.io.PrintWriter; import java.io.FileNotFoundException; import java.io.UnsupportedEncodingException;
...
String kodovani = "windows-1250";
String nazevSouboru = "vystup.txt";
try (PrintWriter out = new PrintWriter(new File(nazevSouboru), kodovani))
    out.println("Hello world!");
    out.close();
} catch (FileNotFoundException ex) { System.err.println("Soubor "+nazevSouboru+" nenalezen: "+ex.getLocalizedMessage());
} catch (UnsupportedEncodingException ex) { System.err.println("Neznámé kódování "+kodovani+": "+ex.getLocalizedMessage());
}
-  Můžete použít i novější knihovnu java.nioa tříduBufferedWriter
Museli byste si ale sami vyřešit textový zápis celých a desetinných čísel:
Charset kodovani = Charset.forName("windows-1250");
Path cesta = Paths.get("vystup.txt");
BufferedWriter out = Files.newBufferedWriter(cesta, kodovani);
Související třídy:
-  Charset
- informace o kódování souboru
 
-  Files, Paths
- práce s cestami a soubory.
 
Standardní vstup a výstup
- Unixové programy a programy pro textový řádek často potřebují číst data ze standardního vstupu (běžně klávesnice) a zapisovat data na standardní výstup (běžně monitor).
- Pro základní práci mnohdy stačí přímo pracovat se standardním vstupem a výstupem přímo:
- System.out
- Běžně používáme pro výstup do konzole:
System.out.print("Ahoj!");
System.out.println("Vypíše řádek na obrazovku!");
- System.in
- Vyžaduje práci s vyjímkami (může vyhodit IOException), je tedy lepší použít třídu Scanner, pokud to lze.
- Čekání na stisk Enteru:
System.in.read();
- Test stisku libovolné klávesy:
System.in.available() > 0
- System.err
-  Chybový výstup. Na obrazovce se vypíše stejně jako u System.out, ale můžeme ho přesměrovat (viz práce se vstupy a výstupy ve 3. ročínku (Operační systémy):
System.err.println("Nastala chyba zápisu do souboru!");
Související stránky
