Java: Textový vstup a výstup

Z MiS
(Rozdíly mezi verzemi)
Přejít na: navigace, hledání
(Vytvoření stránky)
 
(Opraveno na použití try-with-resources.)
 
(Není zobrazeno 23 mezilehlých verzí od 1 uživatele.)
Řádka 1: Řádka 1:
== BufferedWriter ==
+
[[Category:VSE]][[Category:Informatika]][[Category:Java]]
  
Třída <code>BufferedWriter</code> slouží pro zápis dat do textového výstupu.
+
== Ošetření chyb, výjimky ==
 +
* Při práci se souborem je třeba vždy počítat s&nbsp;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ě]].
  
; Princip:
+
== Čtení ze souboru (<code>Scanner</code>) ==
*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ž psát jednotlivé malé texty hned!
+
  
; Otevření souboru
+
=== Třída <code>Scanner</code> ===
Související třídy:
+
* Pro čtení dat z&nbsp;textových souborů slouží v Javě třída <code>Scanner</code> z&nbsp;balíčku <code>java.util</code>.
* <tt>Charset</tt>
+
* Slouží také pro čtení vstupu z&nbsp;klávesnice v&nbsp;konzolových aplikacích (aplikacích, které běží jen v&nbsp;příkazovém řádku).
** informace o kódování souboru
+
* Zaveden od Javy 5 &mdash; lze použít pro převod hodnot z&nbsp;textového zápisu jako „zapouzdření“ třídy <tt>BufferedReader</tt>.
* <tt>Files</tt>, <tt>Paths</tt>
+
* Výhodou je, že umí automaticky načíst čísla (včetně desetinných) z&nbsp;jejich textové podoby.
** práce s cestami a soubory
+
** umí i otevřít <tt>BufferedWriter</tt>.
+
  
; Metody
+
<div class="Varovani">Třídu Scanner nepoužívejte v&nbsp;programech, které pracují s&nbsp;[[Vlákna v Javě|vlákny]]!</div>
* <code>write(String text)</code>
+
* <code>newLine()</code>
+
** Přidá do výstupu konec řádku. Respektuje národní nastavení a platformové závislosti.
+
* <code>flush()</code>
+
** Provede fyzický zápis stávajícího obsahu bufferu na výstup.
+
* <code>close()</code>
+
** Zavře výstupní soubor.
+
** Provede i <code>flush()</code>.
+
  
Charset kodovani = Charset.charsetForName("utf-8");
+
=== Otevření souboru ===
Path cesta = Paths.get("vystup.txt");
+
* Soubor otevřeme pro čtení tak, že vytvoříme novou instanci třídy <code>Scanner</code> a&nbsp;jako parametr konstruktoru předáme soubor, kterých chceme otevřít.
BufferedWriter out = Files.newBufferedWriter(cesta, kodovani);
+
* 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&nbsp;Poznámkovém bloku Windows, použijte kódování <code>Windows-1250</code>.
out.write("blabla");
+
out.newLine();
+
out.close();
+
  
== Scanner ==
+
; Konstruktory třídy <code>Scanner</code>:
* Třída <code>Scanner</code> slouží ke čtení z textového vstupu &mdash; z klávesnice nebo z textového souboru.
+
* <code>Scanner(BufferedReader otevrenyVstupniStream, String encoding)</code>
* Zaveden od Javy 1.5 &mdash; nahrazuje <tt>BufferedReader</tt>.
+
* <code>Scanner(File vstupniSoubor, String encoding)</code>
 +
* <code>Scanner(Path vstupniSoubor, String encoding)</code>
 +
* ...
 +
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:
 +
*# <code>windows-1250</code>... programy ve Windows (Poznámkový blok, Excel,...),
 +
*# <code>cp852</code>... skripty pro příkazový řádek,
 +
*# <code>uft-8</code>... programátorské nástroje, programy v Linuxu.
  
; Metody:
+
 
 +
<div class="Poznamka">
 +
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 <code>dist</code> v adresáři projektu. ([[Java:_Export_bal%C3%AD%C4%8Dku_JAR#Export_z_NetBeans|viz Export balíčku JAR]]).
 +
</div>
 +
 
 +
=== Metody třídy <code>Scanner</code> ===
 +
 
 +
; Získání dalšího bloku dat ze souboru
 
* <code>next()</code>
 
* <code>next()</code>
** přečte celý řádek až po oddělovač (viz dále)
+
** 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č
 
** při čtení z konzole (klávesnice) čeká na oddělovač
 
** bere jednotlivá slova, oddělená standardně bílým místem
 
** bere jednotlivá slova, oddělená standardně bílým místem
 
* <code>int nextInt()</code>
 
* <code>int nextInt()</code>
 +
* <code>int nextDouble()</code>
 +
** vrací objektový typ <tt>Double</tt>.
 +
** Desetinná čísla je třeba zadávat podle národního nastavení. Pro české nastavení tedy s desetinnou čárkou.
 +
* <code>String nextLine()</code>
 +
** Načte jeden řádek textu až po konec řádku (neřeší nastavení oddělovače/delimiteru).
 +
 +
; Zjištění &mdash; je v&nbsp;souboru další blok dat?
 
* <code>boolean hasNext()</code>
 
* <code>boolean hasNext()</code>
 
** je k dispozici další slovo?
 
** je k dispozici další slovo?
* <code>useDelimiter(String delim)</code>
+
* <code>boolean hasNextInt()</code>
** Například při čtení formátu CSV:
+
** následuje na vstupu celé číslo?
out.useDelimiter(",");
+
* <code>boolean hasNextDouble()</code>
 +
** následuje na vstupu desetinné číslo?
 +
* <code>boolean hasNextLine()</code>
 +
** je na vstupu další celý řádek?
  
; Otevření vstupu:
+
; Další nastavení
*Standardní vstup
+
* <code>useDelimiter(String delim)</code>, resp. <code>useDelimiter(Pattern delim)</code>
  Scanner sc = new Scanner(System.in);
+
** Oddělovač položek na řádku, například:<br /><code>out.useDelimiter(",");</code>
  int i = sc.nextInt();
+
** Jako oddělovač lze použít i [http://cs.wikipedia.org/wiki/Regul%C3%A1rn%C3%AD_v%C3%BDraz regulární výraz (&rarr; Wikipedia.org)] reprezentovaný třídou <code>[https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html Pattern]</code>.
  vstup=input.next();
+
** Pro načítání jednoduchého CSV lze použít (pozor, není to plnohodnotné čtení CSV, ale mnohdy stačí):
*Ze souboru:
+
out.useDelimiter("\\s*[;,\n\r\t]\\s*")
  Scanner sc = new Scanner(new File("myNumbers"));
+
 
  while (sc.hasNextLong()) {
+
; Ukončení práce se souborem
 +
* <code>close()</code>
 +
** Ukončení práce se souborem &ndash; 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());
 +
}
 +
 
 +
<div class="Poznamka">
 +
Pokud zadáte pouze název souboru, hledá se soubor v&nbsp;aktuální složce. Která složka je aktuální:
 +
* Při spuštění z&nbsp;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>).
 +
* 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>, 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>
 +
 
 +
 
 +
=== 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()) {
 
     ...
 
     ...
     long aLong = sc.nextLong();
+
     String radek = sc.nextLine();
 
     ...
 
     ...
 
  }
 
  }
 +
sc.close();
  
 +
=== Příklad: Načtení jednoho čísla z&nbsp;klávesnice ===
 +
* Použijte pouze v&nbsp;aplikacích pro příkazový řádek (ne v Greenfootu nebo aplikacích s&nbsp;grafickým uživatelským prostředím).
 +
Scanner sc = new Scanner(System.in);
 +
int i = sc.nextInt();
 +
String text = input.next();
 +
sc.close();
  
== Viz také ==
+
 
 +
 
 +
 
 +
== Zápis do souboru (<tt>PrintWriter</tt>) ==
 +
 
 +
Třída <code>PrintWriter</code> 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);
 +
 
 +
<div class="Poznamka">
 +
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&nbsp;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: <code>String nazev = "C:\\temp\\data.txt";</code>.
 +
</div>
 +
 
 +
; Metody
 +
* <code>println(String text)</code>
 +
** Přidá řádek do výstupního souboru.
 +
* <code>flush()</code>
 +
** Provede fyzický zápis stávajícího obsahu bufferu na výstup.
 +
* <code>close()</code>
 +
** Zavře výstupní soubor.
 +
** Provede i <code>flush()</code>.
 +
 
 +
=== Příklad &mdash; 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());
 +
}
 +
 
 +
 
 +
<div class="Poznamka">
 +
; Můžete použít i&nbsp;novější knihovnu <code>java.nio</code> a&nbsp;třídu <code>BufferedWriter</code>
 +
Museli byste si ale sami vyřešit textový zápis celých a&nbsp;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:
 +
* <tt>Charset</tt>
 +
** informace o kódování souboru
 +
* <tt>Files</tt>, <tt>Paths</tt>
 +
** práce s cestami a soubory.
 +
</div>
 +
 
 +
== Standardní vstup a výstup ==
 +
* Unixové programy a programy pro textový řádek často potřebují číst data ze [[Vstup a výstup procesů, přesměrování|standardního vstupu]] (běžně klávesnice) a zapisovat data na [[Vstup a výstup procesů, přesměrování|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 <tt>IOException</tt>), je tedy lepší použít třídu [[#Vstup (Scanner)|<tt>Scanner</tt>]], 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&nbsp;<code>System.out</code>, ale můžeme ho přesměrovat (viz práce se vstupy a&nbsp;výstupy ve 3.&nbsp;ročínku (Operační systémy):
 +
System.err.println("Nastala chyba zápisu do souboru!");
 +
 
 +
== Související stránky ==
 
* [[Práce se soubory v Javě]]
 
* [[Práce se soubory v Javě]]
 +
* [[Výjimky v Javě]]
 +
  
  

Aktuální verze z 7. 11. 2022, 10:07


Obsah

Ošetření chyb, výjimky

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
} 

Čtení ze souboru (Scanner)

Třída Scanner

Třídu Scanner nepoužívejte v programech, které pracují s vlákny!

Otevření souboru

Konstruktory třídy Scanner

Kódování národních znaků:


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
Zjištění — je v souboru další blok dat?
Další nastavení
out.useDelimiter("\\s*[;,\n\r\t]\\s*")
Ukončení práce se souborem

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

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)
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

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.nio a třídu BufferedWriter

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

System.out
System.out.print("Ahoj!");
System.out.println("Vypíše řádek na obrazovku!");
System.in
System.in.read();
System.in.available() > 0
System.err
System.err.println("Nastala chyba zápisu do souboru!");

Související stránky


Zdroje

  1. JavaPractices.com → Reading and writing text files
  2. Java Tutorial → Scanner
Osobní nástroje
Jmenné prostory
Varianty
Akce
Výuka
Navigace
Nástroje