Lekce 2 - Úvod do práce se soubory v Javě
V minulém dílu našeho seriálu tutoriálů o Javě, Výjimky v Javě, jsme si vysvětlili výjimky, které k práci se soubory nutně potřebujeme, protože díky nim můžeme reagovat na případné chyby.
V dnešním Java tutoriálu si povíme něco o souborech a o právech k zápisu na moderních operačních systémech. Také si ukážeme tvorbu zástupného objektu pro soubor, se kterým chceme pracovat.
Data, resp. objekty uložené v paměti, se samozřejmě s vypnutím aplikace ztratí. Pokud chceme zajistit, aby data byla tzv. perzistentní (trvalá), musíme je při ukončení programu uložit a při načtení programu opět načíst. K ukládání dat existuje mnoho způsobů, každý má svoje výhody a nevýhody.
Data naší aplikace můžeme ukládat následujícími způsoby:
- Textové soubory s jednoduchou strukturou (např.
.txt
a.csv
). - Textové soubory s vnitřní hierarchií (např.
.xml
nebo.json
). - Soubory binárního typu (otisk paměti do souboru).
- Databáze.
Historicky jsou v Javě k práci se soubory k dispozici dvě různá API:
- starší
java.io.*
, jehož středobodem je třídaFile
- novější
java.nio.*
, který se točí kolem třídPath
aFiles
Obě tyto API spolu koexistují. Ačkoliv se doporučuje v novém kódu používat nové API, tak se v praxi často setkáme s potřebou použít i to starší, takže se hodí znát obě. V našem kurzu se budeme zaměřovat na nové API, ale místy si ukážeme, jak by se daná věc dělala pomocí staršího API.
Práva k zápisu na disk v moderních operačních systémech
Všechny moderní operační systémy mají nějaký systém přístupových práv k souborům uloženým na disku. Běžný uživatel má obvykle právo vytvořit soubory a zapisovat do souborů pouze ve svém domovském adresáři. Administrátor může zapisovat kamkoliv. Pokud v naší aplikaci zakládáme soubory, musíme je založit tam, kde má uživatel právo zapisovat.
V reálné aplikaci se uživatele nejprve zeptáme, kde chce
nový soubor vytvořit. Poté zkontrolujeme, zda může do dané lokace
zapisovat. V naších lekcích, v zájmu jednoduchosti, tento krok
přeskočíme. Všechny soubory budeme zakládat v podadresáři
itnetwork
v domovském adresáři uživatele.
Domovský adresář uživatele
Domovský adresář uživatele se nachází v každém systému na jiném místě. Jelikož se snažíme tvořit multiplatformní aplikace, vyhneme se specifickým cestám k souborům v jednotlivých operačních systémech. Java nám k tomu dává prostředky.
Domovský adresář uživatele zjistíme tímto kódem:
System.getProperty("user.home");
Windows systémy
V systémech Windows výše uvedený kód vrátí:
C:\Users\vase_jmeno\
Všimněme si oddělovače adresářů \
, kterým
je zpětné lomítko. Windows jsou také specifické v
označování disků písmeny (C, D, ...).
Linux systémy
V systémech Linux výše uvedený kód vrátí:
/home/vase_jmeno/
Operační systémy, které se hlásí k unixové tradici,
používají pro oddělovač adresářů dopředné lomítko
/
.
MacOS systém
V systému MacOS výše uvedený kód vrátí:
/Users/vase_jmeno
Systém MacOS používá pro oddělovač adresářů také
dopředné lomítko /
.
Vytvoření Path
z
nového API java.nio.*
Základem úspěšné práce se soubory v Javě je mít správně vytvořenou
instanci třídy Path
(při použití novějšího
API), nebo File
(při použití staršího API). Tato instance
třídy reprezentuje cestu k souboru, se kterým chceme
pracovat. Čtení souboru, nebo zápis do souboru pak probíhá za pomocí této
instance.
Pojďme se tedy nejprve podívat na to, jak správně vytvořit instanci
třídy Path
. K vytvoření instance třídy Path
slouží statická metoda of()
volaná na třídě
Path
:
Path cesta = Path.of(cesta_k_souboru);
Příklad
Například cestu k souboru soubor.txt
, v podadresáři
itnetwork
, v našem domovském adresáři definujeme takto:
Path cesta = Path.of(System.getProperty("user.home"), "itnetwork", "soubor.txt");
V kódu neřešíme specifické cesty k souboru pro jednotlivé
operační systémy. System.getProperty()
dosadí správnou cestu
pro platformu, na které je aplikace spuštěna.
Instance třídy Path
je ukazatel na místo na
disku, kde může, ale nemusí daný soubor být. Taktéž nemusí
existovat všechny adresáře v cestě k souboru. Například v našem
příkladu je možné, že ještě nemáme v našem domovském adresáři
adresář itnetwork
.
Kontrola adresářů
Pojďme se tedy nejprve ujistit, že všechny potřebné adresáře opravdu
existují a případně je vytvořit. K tomuto účelu slouží
statická metoda createDirectories()
ze třídy
Files
:
Path cesta = Path.of(System.getProperty("user.home"), "itnetwork", "soubor.txt"); Files.createDirectories(cesta.getParent());
Metoda getParent()
vrací adresář, ve kterém se nachází
soubor.txt
. V našem příkladu je to adresář
itnetwork
. Metoda createDirectories()
vytvoří celou
potřebnou hierarchii adresářů včetně itnetwork
.
Pokud by některý adresář již existoval, metoda
createDirectories()
vytvoření adresáře přeskočí bez
vyvolání výjimky. Proto je vhodné ji použít při každém definování
cesty k souboru.
Vytvoření File
ze staršího API java.io.*
Při použití staršího API pracujeme s třídou File
.
Vytvoření samotné instance je zde velmi podobné:
File cesta = new File("cesta_k_souboru");
Na rozdíl od třídy Path
, třída
File
očekává cestu k souboru jako jeden String
.
Příklad
Stejně jako v případě Path
, i zde můžeme využít
System.getProperty()
pro získání cesty k domovskému
adresáři. Naši cestu k souboru soubor.txt
, v
podadresáři itnetwork
, v našem domovském adresáři zde
definujeme takto:
File cesta = new File(System.getProperty("user.home") + File.separator + "itnetwork" + File.separator + "soubor.txt");
Pomocí File.separator
vytvoříme platnou cestu
pro jakoukoliv platformu.
Kontrola adresářů
Stejně jako v případě Path
i nyní potřebujeme
zkontrolovat, zda existují všechny definované adresáře. K
tomu využijeme metodu mkdirs()
, kterou tentokrát zavoláme na
instanci třídy File
:
File cesta = new File(System.getProperty("user.home") + File.separator + "itnetwork" + File.separator + "soubor.txt"); cesta.getParentFile().mkdirs();
Před samotným zavoláním mkdirs()
zavoláme
metodu getParentFile()
. Metoda getParentFile()
vrátí
adresář, ve kterém se bude nacházet soubor.txt
.
Převeditelnost Path
<->
File
Třídy Path
a File
nabízí snadnou konverzi mezi
sebou.
Konverze Path
na
File
Pro převedení cesty k souboru z instance třídy Path
na
instanci třídy File
, zavoláme metodu toFile()
na
instanci třídy Path
:
Path path = Path.of(...); File file = path.toFile();
Konverze File
na
Path
Pro převedení cesty k souboru z instance třídy File
na
instanci třídy Path
, zavoláme metodu toPath()
na
instanci třídy File
:
File file = new File(...);
Path path = file.toPath();
Nyní již tedy víme jak správně vytvořit instance tříd
Path
a File
pro použití na jakémkoliv operačním
systému.
Nic nám již nebrání, abychom si příště, Práce s textovými soubory v Javě, ukázali práci s prvním formátem souborů, budou to textové soubory.