Lekce 2 - Třídy pro práci se soubory v Kotlin
V minulém dílu našeho Kotlin tutoriálu, Použití výjimek při práci se soubory v Kotlin, 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 Kotlin tutoriálu si uvedeme jednotlivé typy souborů a třídy pro práci s nimi. Podíváme se na práva 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.
Možnosti ukládání a načítání dat
Data, resp. objekty uložené v paměti, se samozřejmě s vypnutím aplikace ztratí. Pokud chceme zajistit, aby data byla 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.
K práci se soubory v Kotlin využijeme dvě různá API z Javy:
- Starší
java.io.*
, jehož středobodem je třídaFile
- novější a
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ší. Hodí se tedy znát obě.
Kotlin upřednostňuje použití třídy Path
, pro
kterou implementoval balíček kotlin.io.path.*
. Odpovídající
API je vždy třeba do projektu importovat. Pokud používáte rozumné IDE,
samo vás na to upozorní a importy nabídne a doplní.
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š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.
Domovský adresář uživatele zjistíme tímto kódem:
System.getProperty("user.home")
Podívejme se, jaký dostaneme výstup v jednotlivých systémech, pokud jej necháme vypsat:
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. Jak uvidíme níže, ostatní operační
systémy používají pro oddělovač adresářů lomítko
dopředné /
. 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/
MacOS systém
V systému MacOS výše uvedený kód vrátí:
/Users/vase_jmeno
Vytvoření Path
z API kotlin.io.path.Path
Základem úspěšné práce se soubory v Kotlin, 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). Ta
reprezentuje cestu k souboru, se kterým chceme pracovat.
Čtení souboru, nebo zápis do souboru pak probíhá za pomoci této
instance.
Pojďme se tedy nejprve podívat na to, jak správně vytvořit instanci
třídy Path
:
val cesta = Path(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:
val cesta = Path(System.getProperty("user.home"), "itnetwork", "soubor.txt")
V kódu neřešíme specifické cesty k souboru pro jednotlivé
operační systémy. Díky System.getProperty()
získáme
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
:
val cesta = Path(System.getProperty("user.home"), "itnetwork", "soubor.txt") Files.createDirectories(cesta.parent)
Metoda parent
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é. Na rozdíl od třídy
Path
, třída File
očekává cestu k souboru jako
jeden String
:
val cesta = File("cesta_k_souboru")
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:
val cesta = 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()
spolu s metodou
parentFile
, která určuje nadřazený adresář. Metody tentokrát
zavoláme na instanci třídy File
:
val cesta = File(System.getProperty("user.home") + File.separator + "itnetwork" + File.separator + "soubor.txt") cesta.parentFile.mkdirs()
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
:
val path = Path(System.getProperty("user.home"), "itnetwork", "soubor.txt") val 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
:
val file = File(System.getProperty("user.home") + File.separator + "itnetwork" + File.separator + "soubor.txt") val 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 v příštím dílu, Práce s textovými soubory v Kotlin, ukázali práci s prvním formátem souborů, budou to textové soubory.