Lekce 14 - Práce se soubory a složkami v Kotlin - Třída File
V minulé lekci, Pokročilé techniky pro práci s výjimkami v Kotlin, jsme dokončili výjimky. Ukázali jsme si jejich řetězení a další užitečné techniky
Dnes si popíšeme třídy v Kotlin, které nejsou nijak závislé na typu
souboru a jejich použití je tedy obecné. Umožňují pracovat se soubory a
složkami na úrovni operačního systému, což jistě budeme v našich
aplikacích potřebovat. V této lekci našeho tutoriálu si představíme
třídu File
, její metody a použití.
Absolutní vs. relativní cesta
Než se pustíme do popisu třídy File
, v krátkosti si něco
řekneme o absolutní a relativní cestě. Je to čistě pro pořádek, abychom
měli jasno.
Absolutní cesta
Absolutní cesta začíná kořenovým prvkem souborového systému. V
případě Windows to bude C:\\
nebo D:\\
, pro Linux
to bude velice jednoduše /
. Absolutní cesta nepotřebuje žádné
další informace k určení umístění souboru. Vše je na jednom místě.
Problém ale je, že cesta je závislá na platformě. Jak již bylo naznačeno,
pro Windows a Linux se liší. Proto doporučuji absolutní cesty v ideálním
případě nepoužívat. Případně pouze pro soubory s nastavením
programu.
Relativní cesta
Relativní cesta nezačíná v kořeni souborového systému. Na místo toho
se počítá v závislosti k nějakému existujícímu prvku, nejčastěji k
aktuálnímu programu, např. obrazky/
. Toto je rozhodně způsob,
kudy jít v případě práce se soubory v programu.
Třída File
Třídu File
poskytuje Java již od první verze. Můžeme ji
tedy bez problému využít i pro tvorbu našich Kotlin aplikací. Postupem
času se však ukázalo, že má nějaké "mouchy", které vyústily ve
vytvoření nového API. To si představíme v dalších lekcích.
Třída File
reprezentuje jak soubor, tak i
složku. Pro práci se souborem či složkou je potřeba
vytvořit novou instanci. To lze provést velmi jednoduše:
val file = File("soubor.txt")
Konstruktor má celkem 4 přetížení:
File(String pathname) File(String parent, String child) File(File parent, String child) File(URI uri)
V prvním případě lze dosadit jak absolutní, tak relativní cestu. Pokud použijete relativní cestu, výsledek se bude vždy počítat z použitého souboru.
Použitým souborem se myslí výsledný .kt
soubor, ne *.class
.
Druhé přetížení přijímá dva řetězce. První řetězec představuje
cestu k rodiči a může být jak relativní, tak absolutní. Druhý parametr je
cesta relativní k rodiči v prvním parametru. Rodič je jakákoliv nadřazená
složka, například C://
. Potomek je soubor nebo složka, která
se nachází v nadřazené složce, například C://soubor.txt
.
Třetí přetížení se liší v prvním parametru, kterým je nyní jiná
instance třídy File
.
Poslední přetížení přijímá tzv. URI
. Je to zkratka pro
Uniform Resource Identifier.
URI si nebudeme plést s URL. URI je standard pro identifikaci dokumentů, využívající schéma popsané níže. URL je "podmnožina" URI a obsahuje informace, jak zpracovat zdroje z nějakého umístění.
Kompletní syntax pro URI vypadá následovně:
scheme:[//[user:password@]host[:port]][/]path[?query][#fragment]
Toto je obecné schéma. Nám postačí pouze základní, kde za část
scheme
dosadíme file
a pak až cestu:
file:/tmp/soubor.txt
S tímto přístupem se nejčastěji setkáme při použití
různých obrázků, zvuků a dalších souborů. K těmto souborům obvykle
přistupujeme pomocí metody getClass().getResource(String name)
.
Tato metoda vrací právě URI, které předáme konstruktoru třídy
File
.
Nejčastěji ale budeme pracovat s prvním přetížením konstruktoru.
Metody třídy File
Metody si roztřídíme do několika kategorií:
- get,
- set,
- can,
- is,
- funkční.
GET metody
Máme k dispozici následující GET metody, které si všechny hned prakticky vyzkoušíme:
getAbsolutePath(): String
- vrátí absolutní cestu k souboru,getCanonicalPath(): String
- vrátí canonizovanou cestu k souboru,getFreeSpace(): long
- vrátí počet volných bytů v oddílu, ve kterém se soubor nachází,getName(): String
- vrátí název souboru,getParent(): String
- vrátí absolutní cestu k rodiči, nebonull
, pokud soubor je sám rodič,getParentFile(): File
- vrátí instanci třídyFile
reprezentující rodiče aktuálního souboru,getPath(): String
- vrátí cestu k souboru, ale předem není jisté, v jakém tvaru ji dostaneme, proto je lepší používatgetCanonicalPath()
,getTotalSpace(): long
- vrátí celkový počet bytů v oddílu, ve kterém se soubor nachází,getUsableSpace(): long
- vrátí počet použitelných bytů pro aktuální virtuální stroj, výsledek je přesnější, než z metodygetFreeSpace()
.
Pro jistotu si napíšeme i příklady použití. Vytvoříme jednu instanci
třídy File
a zavoláme nad ní veškeré GET metody.
Pro demonstraci jsem schválně vytvořil nešikovnou složkovou strukturu, aby byly vidět rozdíly mezi jednotlivými metodami. Složky jsou vytvořeny následovně:
src |---cz | |---itnetwork | |---souboryslozky | |---App.java |---soubory | |---soubor.txt
Instanci třídy File
vytvoříme takto:
val file = File("../../../soubory/soubor.txt")
Schválně jsme použili několikrát sekvenci ../
,
která nás vrátí o složku zpět vzhledem k aktuální složce, aby byl
výsledek zajímavější.
Výstup jednotlivých metod:
getAbsolutePath(): /tmp/itn/soubory-slozky/../../../soubory/soubor.txt getCanonicalPath(): /soubory/soubor.txt getFreeSpace(): 0 getName(): soubor.txt getParent(): ../../../soubory getParentFile(): ../../../soubory getPath(): ../../../soubory/soubor.txt getTotalSpace(): 0 getUsableSpace(): 0
SET metody
SET metody, jak název napovídá, souborům nastavují nějaké vlastnosti. Jsou to:
setExecutable(boolean executable, boolean ownerOnly): boolean
- nastaví, zda je soubor spustitelný, druhý parametr uvádět nemusíme, pak má hodnotutrue
a spustitelnost nastaví pouze aktuálnímu uživateli,setLastModified(long time): boolean
- nastaví datum poslední změny souboru,setReadable(boolean readable, boolean ownerOnly): boolean
- nastaví, zda je soubor možné číst, pro druhý parametr platí to samé, jako u první metody,setReadOnly(): boolean
- jednosměrná metoda, pomocí které se nastaví soubor pouze pro čtení a nepůjde do něj zapisovat,setWritable(boolean writable, boolean ownerOnly): boolean
- nastaví, zda je možné do souboru zapisovat, pro druhý parametr platí to samé jako u první metody.
CAN metody
CAN metody máme následující:
canExecute(): boolean
- vrátítrue
, pokud lze soubor spustit,canRead(): boolean
- vrátítrue
, pokud lze ze souboru číst,canWrite(): boolean
vrátítrue
, pokud lze do souboru zapisovat.
IS metody
Pomocí IS metod se můžeme ptát na tyto věci:
isAbsolute(): boolean
- vrátítrue
, pokud byla instance vytvořena za pomoci absolutní cesty,isDirectory(): boolean
- vrátítrue
, pokud se jedná o složku,isFile(): boolean
- vrátítrue
, pokud se jedná o soubor,isHidden(): boolean
- vrátítrue
, pokud je soubor skrytý.
Funkční metody
Z probíraných metod nám už jenom chybí tvz. funkční metody, tedy takové metody, které něco provádí se samotným souborem a které budeme využívat nejčastěji:
toURI(): URI
- vytvoří URI z použité instance souboru,createNewFile(): boolean
- vytvoří nový soubor pokud neexistuje a vrátítrue
, pokud se soubor podařilo vytvořit,delete(): boolean
- smaže soubor a vrátítrue
, pokud se jej smazat podařilo,deleteOnExit(): void
- smaže soubor až po ukončení programu,exists(): boolean
- vrátítrue
, pokud soubor existuje,length(): long
- vrátí velikost souboru v bytech,list(): String[]
- vrátí pole absolutních cest souborů ve složce,listFiles(): File[]
- vrátí pole instancí souboru ve složce,mkdir(): boolean
- pokusí se vytvořit složku a vrátítrue
, pokud se složka vytvořila,mkdirs(): boolean
- pokusí se vytvořit všechny složky v cestě, opět vrátítrue
, pokud se všechny složky vytvořily,renameTo(File dest): boolean
- přejmenuje soubor na nové jméno, což lze chápat jako "přesun" souboru z jednoho místa na druhé, metoda je platformě závislá a nelze použít pro přesun souboru mezi dvěma souborovými systémy,toPath(): Path
- vytvoří novou instanci rozhraníPath
.
Problémy File
API
File
API trpí následujícími nedostatky:
- Valná většina metod vrací pouze
false
v případě, že se něco nepovede. Problém je, že neznáme příčinu neúspěchu. - Přejmenování souboru nefunguje na všech platformách stejně.
- API nepodporuje symbolické linky.
- V API chybí podpora metadat (oprávnění, vlastník souboru...).
V příští lekci, Práce se soubory a složkami v Kotlin - Nové API, se seznámíme s novými třídami pro práci se
soubory a složkami, které problémy řeší nedostatky starší třídy
File
.