Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.
Pouze tento týden sleva až 80 % na e-learning týkající se C a C++. Zároveň využij akce až 80 % zdarma při nákupu e-learningu - více informací.
discount week 80 + hiring

Lekce 3 - Práce s textovými soubory v Javě

V minulém dílu seriálu tutoriálů pro Javu, Úvod do práce se soubory v Javě, jsme si ukázali, jak fungují přístupová práva v operačních systémech a jak se vytvářejí instance tříd Path a File.

V dnešním Java tutoriálu si vysvětlíme práci s textovými soubory pomocí staršího API java.io a novějšího API java.nio.

Nejjednodušší cestou, jak uložit data aplikace na pevný disk, je využít textové soubory. Se soubory s příponou .txt jsme se jistě všichni již setkali. Text je v nich uložen jednoduše na jednotlivých řádcích. K oddělení řádků se využívá speciálních znaků, které jsou bohužel specifické pro každý operační systém. Toto však za nás naštěstí vyřeší Java.

API java.io

Pojďme se nejprve podívat na starší způsob práce se soubory pomocí API java.io.

Zápis do nového textového souboru

Vytvoříme si nový projekt s názvem TextoveSoubory a v něm třídu Main s obvyklou metodou main(). K zápisu do textového souboru slouží třída FileWriter, která se ale obvykle obaluje do třídy BufferedWriter. Objekt BufferedWriter používá k zápisu na disk vyrovnávací paměť a je tudíž výrazně výkonnější. Také poskytuje metodu newLine(). Tato metoda vloží do souboru správný znak konce řádku, nezávisle na operačním systému.

Nejprve si ale vytvoříme instanci třídy File, tak jak jsme si to ukázali v této lekci. Soubor pojmenujeme třeba oldapi.txt.

File file = new File(System.getProperty("user.home") + File.separator + "itnetwork" + File.separator + "oldapi.txt");
file.getParentFile().mkdirs();

Nyní vytvoříme blok try-with-resources a v něm novou instanci typu BufferedWriter. Jak již víme z předchozích dílů, blok try-with-resources se nám automaticky postará o zavření souboru po dokončení zápisu/čtení. Do konstruktoru vložíme instanci objektu FileWriter. Samotný objekt FileWriter potřebuje objekt typu File, který jsme vytvořili výše.

try (BufferedWriter bw = new BufferedWriter(new FileWriter(file))) {
} catch (Exception e) {
    System.out.println("Do souboru se nepovedlo zapsat.");
}

Náš objekt BufferedWriter je nyní nasměrovaný na správný soubor. Nový řádek zapíšeme pomocí metody write(). Odřádkování v souboru docílíme metodou newLine(). Po dokončení zápisu musíme zavolat metodu flush(), která se stará o vyprázdnění bufferu. S tím se zde nebudeme zatěžovat, postačí nám vědět, že námi zapsané řádky mohou zůstat chvíli ve vyrovnávací paměti a my pomocí flush() vynutíme jejich zápis.

Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

Kód se nám tedy rozrostl a vypadá takto:

File file = new File(System.getProperty("user.home") + File.separator + "itnetwork" + File.separator + "oldapi.txt");
file.getParentFile().mkdirs();
try (BufferedWriter bw = new BufferedWriter(new FileWriter(file))) {
    bw.write("První řádek");
    bw.newLine();
    bw.write("Tento text je na druhém řádku");
    bw.newLine();
    bw.write("A do třetice.");
    bw.newLine();
    bw.flush();
} catch (Exception e) {
    System.out.println("Do souboru se nepovedlo zapsat.");
}

Po spuštění se vytvoří soubor oldapi.txt v našem domovském adresáři v podadresáři itnetwork. Můžeme se tam podívat a běžným textovým editorem se přesvědčit, že opravdu obsahuje náš text:

Zápis textových souborů v Javě

Připsání textu do existujícího souboru

Takto do existujícího souboru připíšeme nový řádek:

try (BufferedWriter bw = new BufferedWriter(new FileWriter(file, true))) {
    bw.write("Připsaný řádek");
    bw.newLine();
    bw.flush();
} catch (Exception e) {
    System.out.println("Do souboru se nepovedlo zapsat.");
}

Druhým parametrem konstruktoru objektu FileWriter s hodnotou true, specifikujeme připsání do existujícího souboru, jehož původní obsah zůstane nezměněn.

Čtení existujícího souboru

Zbývá nám již jen umět soubor načíst. Není to o nic složitější, než zápis a opět k tomu máme v Javě připravenou třídu, konkrétně BufferedReader. Použití je obdobné, namísto metody write() použijeme metodu readLine(), která vrací řádek textu ze souboru a zároveň se přesune na řádek následující. Budeme ji tedy volat v cyklu while. Podmínka pro ošetření vyjetí ze souboru je možná krkolomnější, kontrolujeme, zda proběhlo přiřazení nové řádky do proměnné.

Kód k výpisu obsahu souboru do konzole vypadá takto:

try (BufferedReader br = new BufferedReader(new FileReader(file))) {
    String s;
    while ((s = br.readLine()) != null) {
        System.out.println(s);
    }
} catch (Exception e) {
    System.out.println("Chyba při čtení ze souboru.");
}

Kód celého našeho programu vypadá takto:

// zápis do souboru
File file = new File(System.getProperty("user.home") + File.separator + "itnetwork" + File.separator + "oldapi.txt");
file.getParentFile().mkdirs();
try (BufferedWriter bw = new BufferedWriter(new FileWriter(file))) {
    bw.write("První řádek");
    bw.newLine();
    bw.write("Tento text je na druhém řádku");
    bw.newLine();
    bw.write("A do třetice.");
    bw.newLine();
    bw.flush();
    System.out.println("Do souboru bylo zapsáno");
} catch (Exception e) {
    System.out.println("Do souboru se nepovedlo zapsat.");
}

// připsání textu do existujícího souboru
try (BufferedWriter bw = new BufferedWriter(new FileWriter(file, true))) {
    bw.write("Připsaný řádek");
    bw.newLine();
    bw.flush();
    System.out.println("Do souboru bylo připsáno");
} catch (Exception e) {
    System.out.println("Do souboru se nepovedlo zapsat.");
}

// výpis obsahu souboru
System.out.println("Vypisuji celý soubor:");
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
    String s;
    while ((s = br.readLine()) != null) {
        System.out.println(s);
    }
} catch (Exception e) {
    System.out.println("Chyba při čtení ze souboru.");
}

A výsledek:

Zápis a čtení textových souborů v Javě

API java.nio

Teď se podíváme na novější způsob práce se soubory pomocí API java.nio.

Zápis do nového textového souboru

Nejprve si vytvoříme instanci třídy Path. Soubor pojmenujeme třeba newapi.txt:

Path path = Path.of(System.getProperty("user.home"), "itnetwork", "newapi.txt");

K zápisu do souboru použijeme statickou metodu writeString() ze třídy Files. Nezapomeneme nejprve vytvořit všechny potřebné adresáře a zachytávat případnou výjimku. Jako oddělovač řádku použijeme univerzální oddělovač pomocí metody lineSeparator().

Metoda writeString() přijímá dva a více parametrů. První parametr je typu Path, čili soubor, do kterého chceme zapisovat. Druhý parametr je typu String, čili text, který chceme zapisovat. Poté následují nepovinné parametry typu StandardOpenOption, kterými metodě říkáme, jakým způsobem se má soubor otevřít.

Způsoby otevření souboru

Nejpoužívanější volby výčtového typu StandardOpenOption pro způsoby otevření souboru jsou tyto:

  • CREATE - vytvoří nový soubor, nevyhazuje chybu, pokud už existuje
  • CREATE_NEW - vytvoří nový soubor, vyhodí chybu, pokud soubor už existuje
  • TRUNCATE_EXISTING - při otevření vymaže obsah souboru
  • APPEND - otevře soubor pro přidávání obsahu

V následujícím příkladu při zápisu prvního řádku použijeme volbu CREATE a TRUNCATE_EXISTING, aby se soubor vytvořil a existující soubor napřed vymazal. Každý další zápis už děláme pomocí volby APPEND, aby se zapisovaný text typu String přidal na konec souboru:

try {
    Files.createDirectories(path.getParent());
    Files.writeString(path, "První řádek" + System.lineSeparator(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
    Files.writeString(path, "Tento text je na druhém řádku" + System.lineSeparator(), StandardOpenOption.APPEND);
    Files.writeString(path, "A do třetice" + System.lineSeparator(), StandardOpenOption.APPEND);
} catch (IOException ex) {
    System.out.println("Chyba při zápisu do souboru: " + ex.getMessage());
}

Stejně jako v případě staršího API java.io, se nám i nyní po spuštění programu vytvoří nový soubor s názvem newapi.txt obsahující tři řádky textu. Můžeme si to ověřit libovolným textovým editorem.

Připsání textu do existujícího souboru

Připsání řádků do již existujícího souboru děláme pomocí volby APPEND:

try {
    Files.writeString(path, "Tento text je na posledním řádku" + System.lineSeparator(), StandardOpenOption.APPEND);
} catch (IOException ex) {
    System.out.println("Chyba při zápisu do souboru: " + ex.getMessage());
}

Čtení existujícího souboru

Ke čtení řádků z textového souboru použijeme metodu readAllLines() opět ze třídy Files. Tato metoda vrací kolekci List<String>:

try {
    List<String> lines = Files.readAllLines(path);
    lines.forEach(System.out::println);
} catch (IOException ex) {
    System.out.println("Chyba při čtení souboru: " + ex.getMessage());
}

V příští lekci , Uložení objektů do CSV v Javě, vytvoříme formulářovou aplikaci s databází uživatelů, která ukládá instance do textových souborů ve formátu CSV.


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 834x (3.35 kB)
Aplikace je včetně zdrojových kódů v jazyce Java

 

Předchozí článek
Úvod do práce se soubory v Javě
Všechny články v sekci
Soubory a síť v Javě
Přeskočit článek
(nedoporučujeme)
Uložení objektů do CSV v Javě
Článek pro vás napsal David Čápka
Avatar
Uživatelské hodnocení:
26 hlasů
David je zakladatelem ITnetwork a programování se profesionálně věnuje 13 let. Má rád Nirvanu, sushi a svobodu podnikání.
Unicorn university David se informační technologie naučil na Unicorn University - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity

 

 

Komentáře
Zobrazit starší komentáře (18)

Avatar
Rasinsky
Člen
Avatar
Rasinsky:26.7.2018 11:04

viem ze starsie, ale tak dalsie mozne riesenie:

Scanner fileScanner = new Scanner(UserFile);

while (fileScanner.hasNext()) {
        text =text + " " +fileScanner.next();
        }
fileScanner.close();    //nezabudat na zatvorenie scanner-u

co sa tyka escapovania asi to bude aj s NetBeans, pouzivam Eclipse, a nacita to v pohode, bez escapovania.

UserFile

pokus aaa funguje

aj prazdny riadok
"uvodzovky"
\t \n

vystup

pokus aaa funguje aj prazdny riadok "uvodzovky" \t \n

 
Odpovědět
26.7.2018 11:04
Avatar
MiroslavP
Člen
Avatar
MiroslavP:17.9.2018 21:54

Velmi užitečné a srozumitelné. děkuji.:-)

 
Odpovědět
17.9.2018 21:54
Avatar
Lukáš Kučavík:27.3.2021 19:05

Jsem lehce zmaten. Když se kouknu na internet, tak najdu několik způsobů, které mi narozdíl od těchto opravdu fungují. Rád bych to nějak podrobně popsal ale vůbec netuším kde může být problém. :/

Odpovědět
27.3.2021 19:05
Každý je zodpovědný za svůj život. Ale ne každý je ochoten tuto zodpovědnost přijmout.
Avatar
Odpovídá na Lukáš Kučavík
Lukáš Kučavík:27.3.2021 19:31

Omluvte mě prosím. To jsem klasický já, aniž bych pořádně vyzkoušel všechny možnosti a prohlédl si pořádně svůj kód, tak hned žádám o pomoc. Kéžby šel komentář vymazat :)

Odpovědět
27.3.2021 19:31
Každý je zodpovědný za svůj život. Ale ne každý je ochoten tuto zodpovědnost přijmout.
Avatar
Erik Nisler
Člen
Avatar
Erik Nisler:18.11.2021 14:47

Ahoj,

přijde mi zvláštní tato část:
String s;
while ((s = br.readLine()) != null)

Zkoušel jsem to napsat zkráceně:
String s = br.readLine();
while (s != null){}

Ale nefunguje to, přitom mi to přijde totožné, uniká mi něco? Děkuji :)

Odpovědět
18.11.2021 14:47
Co hledáš, to hledá i tebe.
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
Petr Štechmüller
Překladatel
Avatar
Odpovídá na Erik Nisler
Petr Štechmüller:18.11.2021 14:51

Ahoj, ve tvém případě načteš řádek pouze jednou a potom v cyklu kontroluješ pořád dokola stejnou hodnotu. Pokud bys to chtěl takhle rozepsat, musel bys přidat do těla cyklu znovu načtení řádky.

Odpovědět
18.11.2021 14:51
Pokud spolu kód a komentář nekorespondují, budou patrně oba chybné
Avatar
Erik Nisler
Člen
Avatar
Erik Nisler:19.11.2021 9:05

Jasně, pokud to tedy chápu dobře:

V mém případě se do Stringu před whilem natvrdo uloží jen ten první řádek a ten se opakuje donekonečna.

Odpovědět
19.11.2021 9:05
Co hledáš, to hledá i tebe.
Avatar
Tomáš Čermák:13. ledna 14:42

Nevíte prosím, proč mám podrženou write.String červeně - cannot find symbol - symbol: method writeString. NetBeans 12.5

package soubory;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;


/**
 *
 * @author cermak
 */
public class Soubory {

    /**
     * @param args the command line arguments
     * @throws java.io.IOException
     */
    public static void main(String[] args) throws IOException {


        Path path = Paths.get("C:\\Users\\cermak\\ITnetwork\\test.txt");

        try {
            //jestli neexistuje slozka, tak se vytvori
            Files.createDirectories(path.getParent());
            Files.writeString(path, "První řádek" + System.lineSeparator(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
            Files.writeString(path, "Tento text je na druhém řádku" + System.lineSeparator(), StandardOpenOption.APPEND);
            Files.writeString(path, "A do třetice" + System.lineSeparator(), StandardOpenOption.APPEND);

        } catch (Exception e) {

            System.out.println("Nelze zapisovat do souboru");
        }

    }

}
 
Odpovědět
13. ledna 14:42
Avatar
Atrament
Super redaktor
Avatar
Odpovídá na Tomáš Čermák
Atrament:13. ledna 17:07

Viz odpověď na tvůj dotaz u předchozího článku - upgradni verzi Javy aspoň na 11

 
Odpovědět
13. ledna 17:07
Avatar
Odpovídá na Atrament
Tomáš Čermák:13. ledna 19:13

Ajo, to je ono diky :)

 
Odpovědět
13. ledna 19:13
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 28. Zobrazit vše