Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
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í.

Lekce 16 - Práce s vlastními soubory v Kotlin - ZIP archiv

V minulé lekci, Práce se soubory a složkami v Kotlin - Nové API, jsme si ukázali práci se soubory a složkami v Kotlin pomocí tříd zavedených od Javy 7.

Nyní již umíme pracovat se spoustou druhů souborů. Víme, jak je ukládat a otevírat, přehrávat, odchytávat chyby. V dnešním dílu našeho Kotlin tutoriálu si ukážeme další možnost práce se soubory, a to s použitím ZIP archivu.

ZIP archivy

Představme si reálnou aplikaci k evidenci zaměstnanců. Zaměstnanec v ní má textové údaje (jméno, příjmení a email), datum (datum narození), číslo (telefonní číslo) a obrázek (fotografii). Už jen kvůli obrázku může být na první pohled problém všechna tato data uložit, a to ideálně do jednoho jediného souboru. Teoreticky bychom mohli zvolit nějaký binární formát dat (kvůli obrázku) a vložit do něj i textové údaje. Prakticky jsou ale binární soubory poměrně nešikovné a špatně se s nimi reaguje na změny formátu.

Podobné aplikace často využívají k ukládání dat archivy. Vezměme si takový MS-Word a jeho dokumenty s příponou souborů .docx. Když změníme příponu libovolného .docx souboru na .zip, zjistíme, že dokument je ve skutečnosti archiv ZIP, pouze s jinou příponou. Zkuste si to.

Windows skrývají ve výchozím nastavení přípony souborů známých typů, takže místo Dokument.docx vidíme jen Dokument. Nastavení změníme v záložce Zobrazení, v okně Zobrazit či skrýt zaškrtnutím políčka Přípony názvů souborů.

Jako archiv v sobě může soubor obsahovat jednoduše několik souborů a navenek se tváří pro nic netušícího uživatele jako jeden. Přesně archivu ZIP využijeme i k uložení našeho zaměstnance. A místo .zip nastavíme souboru úplně jinou příponu, nabízí se .zamestnanec nebo zkráceně .zam.

Přípona souboru slouží jen k tomu, aby operační systém Windows zjistil, v jaké aplikaci má soubor otevřít, když na něj uživatel poklepe. Většinou platí, že má každý soubor na konci svého názvu tečku a třípísmennou příponu. Ve skutečnosti nemusí mít soubor příponu vůbec žádnou, může jich mít více, mohou být delší než tři znaky a dokonce nemusí vůbec odpovídat tomu, co je v souboru uložené.

My budeme soubor .zip maskovat jako soubor .zam. Zip neponecháme z toho důvodu, aby to uživatele nezmátlo a nezačal soubory rozbalovat a měnit.

Formát souborů .zam

Struktura zazipované složky bude následující:

  • data.zam
    • zamestnanci.xml
    • obrazky/
      • jmenoprijmeni_1.png
      • jmenoprijmeni_2.png

Soubor zamestnanci.xml bude vypadat například takto:

<zamestnanci>
    <zamestnanec>
        <jmeno>Tomáš</jmeno>
        <prijmeni>Šeldosklepa</prijmeni>
        <email>[email protected]</email>
        <telefon>123456789</telefon>
        <narozeni>1.1.1970</narozeni>
    </zamestnanec>
</zamestnanci>

Element <zamestnanci> obalující zaměstnance je zde proto, že aplikace může někdy v budoucnu zpracovávat více zaměstnanců. Nad takovými "drobnostmi" je potřeba při návrhu přemýšlet.

Tvorba aplikace

Vytvořme si nový projekt, formulářovou aplikaci. Pod článkem je k dispozici archiv s projektem. V projektu již jsou vygenerované všechny potřebné formulářové prvky a navěšeny obsluhy tlačítek:

Formulář pro správu zaměstnanců - Soubory a práce s nimi v Kotlin

Třída Zamestnanec

Začneme tím, co by mělo být jasné, tedy vlastnostmi. Náš zaměstnanec bude mít:

  • jméno,
  • příjmení,
  • email,
  • telefon,
  • datum narození
  • a bude mít i fotografii.

Ve třídě si ještě přepíšeme metodu toString(), celý kód pak vypadá takto:

class Zamestnanec @JvmOverloads constructor(
    var jmeno: String = "",
    var prijmeni: String = "",
    var email: String = "",
    var telefon: String = "",
    var narozeniny: LocalDate = LocalDate.now()
) {
    var obrazek: BufferedImage? = null

    override fun toString(): String {
        return "Zamestnanec{jmeno=$jmeno, prijmeni=$prijmeni}"
    }
}

Konstruktor jsme označili anotací @JvmOverloads, protože jej použijeme pro dvě přetížení. První přetížení vytvoří prázdného zaměstnance. Pomocí druhého vytvoříme instanci zaměstnance se všemi údaji, kromě obrázku. Anotací @JvmOverloads pak zajistíme interoperabilitu s Javou, kde bychom museli deklarovat konstruktory dva.

Úprava kontroleru

Do projektu si nyní přidáme kontroler DatabazeKontroler a deklarujeme v něm kolekci zaměstnanců a jednotlivé položky z formuláře:

    class DatabazeKontroler {

    private val zamestnanci = mutableListOf<Zamestnanec>()

    @FXML
    private lateinit var obrazekView: ImageView

    @FXML
    private lateinit var jmenoTextField: TextField

    @FXML
    private lateinit var prijmeniTextField: TextField

    @FXML
    private lateinit var emailTextField: TextField

    @FXML
    private lateinit var telefonTextField: TextField

    @FXML
    private lateinit var datumPicker: DatePicker
}

Metody pro obsluhu tlačítek

Dále si připravíme metodu pro načtení obrázku:

@FXML
private fun nacistObrazek() {
    val fileChooser = FileChooser()                        // Vytvoření průzkumníka souborů
    val soubor: File = fileChooser.showOpenDialog(Stage()) // Otevření dialogového okna průzkumníka souborů
    val obrazekURL: URL = soubor.toURI().toURL()           // Vytvoření URL cesty k souboru
    val obrazek = Image(obrazekURL.toExternalForm())       // Získání obrázku - .png, .jpg, .jpeg...

    obrazekView.image = obrazek                            // Zobrazení vybraného obrázku
}

Pomocí metody FileChooser() vytvoříme průzkumníka souborů, který nám následně umožní vybrat soubor s obrázkem. Do pomocné proměnné si uložíme cestu k obrázku, který následně vytvoříme pomocí třídy Image(). Nakonec jej zobrazíme v našem formuláři.

Doplníme také metodu, která bude sloužit k ukládání uživatelů:

@FXML
private fun ulozZaznam() {
    val jmeno = jmenoTextField.text
    val prijmeni = prijmeniTextField.text
    val email = emailTextField.text
    val telCislo = telefonTextField.text

    /**
     * Nejdříve získáme hodnotu z DatePicker novyUzivatelDatumRegistrace,
     * Poté získáme den, měsíc a rok. Nakonec vytvoříme datum ve formátu "den'.'Měsíc'.'Rok"
     */
    val datePickerValue = datumPicker.value
    val den = datePickerValue.dayOfMonth.toString()
    val mesic = datePickerValue.monthValue.toString()
    val rok = datePickerValue.year.toString()
    val datum = "${den}.${mesic}.${rok}"

    val datumNarozenin: LocalDate = LocalDate.parse(datum, DateTimeFormatter.ofPattern("d'.'M'.'y"))

    val uzivatel = Zamestnanec(jmeno, prijmeni, email, telCislo, datumNarozenin)  // Vytvoření nového zaměstnance

    val obrazek = obrazekView.image
    uzivatel.obrazek = SwingFXUtils.fromFXImage(
        obrazek,
        null
    )                 // SwingFXUtils - Přeloží JavaFX Image do BufferedImage
    zamestnanci.add(uzivatel)

    val fileChooser = FileChooser()               // Vytvoření průzkumníku souborů
    fileChooser.title = "Uložit soubor"
    fileChooser.extensionFilters.addAll(FileChooser.ExtensionFilter("All Files", "*.*"))
    val soubor = fileChooser.showSaveDialog(Stage())
}

Kód obou metod by měl být srozumitelný, za zmínku stojí použití SwingFXUtils pro převedení obrázku do formátu BufferedImage.

Přejděme tedy k poslední metodě pro obsluhu tlačítek našeho formuláře pro načítání záznamů. V metodě nacistZaznam() bude možné vybrat soubor, který chceme načíst a poté zavoláme metodu zobrazUzivatele(), kterou si vzápětí doplníme:

@FXML
private fun nacistZaznam() {
    val fileChooser = FileChooser()                            // Vytvoření průzkumníku souborů
    val soubor: File = fileChooser.showOpenDialog(Stage())     // Otevření dialogového okna průzkumníka souborů

    zobrazUzivatele()
}

Metoda zobrazUzivatele()

Po načtení souboru necháme ve formuláři vypsat uživatele, který byl do kolekce uložen jako první:

private fun zobrazUzivatele(){

jmenoTextField.text = zamestnanci.get(0).jmeno
prijmeniTextField.text = zamestnanci.get(0).prijmeni
emailTextField.text = zamestnanci.get(0).email
datumPicker.value = zamestnanci.get(0).narozeniny
telefonTextField.text = zamestnanci.get(0).telefon
obrazekView.image = SwingFXUtils.toFXImage(zamestnanci.get(0).obrazek, null)
// Pomocí SwingFXUtils opět přeložíme BufferedImage pro zobrazení v JavaFX
}

Nyní máme aplikaci navrženou. Samotné ukládání a načítání ZIP archivu si ukážeme a doplníme příště.

V příští lekci, Práce s vlastními soubory v Kotlin - XML pro ZIP archiv, budeme pokračovat v přípravě formulářové aplikace pro ukládání a načítání ZIP souborů. Doplníme si do ní třídy pro zpracování údajů o zaměstnancích v XML formátu.


 

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 2x (37.34 kB)
Aplikace je včetně zdrojových kódů v jazyce Kotlin

 

Předchozí článek
Práce se soubory a složkami v Kotlin - Nové API
Všechny články v sekci
Soubory a práce s nimi v Kotlin
Přeskočit článek
(nedoporučujeme)
Práce s vlastními soubory v Kotlin - XML pro ZIP archiv
Článek pro vás napsal Filip Studený
Avatar
Uživatelské hodnocení:
1 hlasů
.
Aktivity