Lekce 19 - Práce s vlastními soubory v Javě - Zip archiv
V minulé lekci, Práce se soubory a složkami v Javě - Nové API, jsme si ukázali práci se soubory a složkami v Javě.
Nyní již umíte pracovat se spoustou druhů souborů, umíte je ukládat a otevírat, přehrávat, odchytávat chyby, ... Představte si ovšem reálnou aplikaci k evidenci zaměstnanců. Zaměstnanec bude mít 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 binární soubory poměrně nešikovné a špatně se s nimi reaguje na změny formátu.
Zip
Podobné aplikace často využívají k ukládání dat archivy. Vezměte si
takový MS-Word a jeho dokumenty s příponou souborů .docx
. Když
změníte příponu libovolného .docx
souboru na
.zip
, zjistíte, ž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íte jen
Dokument
. Nastavení změníte v Ovládacích panelech ->
Zobrazit podle: Ikony -> Možnosti složky -> Zrušit zatržítko Skrýt
přípony známých typů.
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í ze
.zamestnanec
nebo pokud se chcete držet třípísmenných, tak jen
.zam
.
Přípona souboru totiž 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ž 3 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 by mohla být následující:
data.zam
zamestnanci.xml
obrazky/
jmenoprijmeni_1.png
jmenoprijmeni_2.png
Soubor zamestnanci.xml
by mohl vypadat následovně:
<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 Zamestnanec
Vytvořte 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.

Třída Zamestnanec
Začneme tím, co by mělo být jasné - vlastnostmi. Náš zaměstnanec bude mít:
- jméno,
- příjmení,
- email,
- telefon,
- datum narození
- a bude mít i fotografii:
public class Zamestnanec { private String jmeno; private String prijmeni; private String email; private String telefon; private LocalDate narozeniny; private BufferedImage obrazek; public Zamestnanec() { this("", "", "", "", LocalDate.now()); } public Zamestnanec(String jmeno, String prijmeni, String email, String telefon, LocalDate narozeniny) { this.jmeno = jmeno; this.prijmeni = prijmeni; this.email = email; this.telefon = telefon; this.narozeniny = narozeniny; } @Override public String toString() { return "Zamestnanec{" + "jmeno=" + jmeno + ", prijmeni=" + prijmeni + '}'; } }
Třída má dva konstruktory. První přetížení vytvoří prázdného zaměstnance. Pomocí druhého konstruktoru vytvoříme instanci zaměstnance se všemi údaji, kromě obrázku.
Gettery a settery
Dále následují pouze gettery a settery pro tyto vlastnosti:
public String getJmeno() { return jmeno; } public void setJmeno(String jmeno) { this.jmeno = jmeno; } public String getPrijmeni() { return prijmeni; } public void setPrijmeni(String prijmeni) { this.prijmeni = prijmeni; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getTelefon() { return telefon; } public void setTelefon(String telefon) { this.telefon = telefon; } public LocalDate getNarozeniny() { return narozeniny; } public void setNarozeniny(LocalDate narozeniny) { this.narozeniny = narozeniny; } public BufferedImage getObrazek() { return obrazek; } public void setObrazek(BufferedImage obrazek) { this.obrazek = obrazek; }
Do formuláře si přidáme proměnnou typu Zamestnanec
, ale
nebudeme ji instancovat:
private Zamestnanec zamestnanec;
Správce zaměstnanců
Abychom dodrželi oddělení logiky a GUI, založíme si novou třídu,
která se bude starat o správu zaměstnanců. Třídu nazvěme jednoduše
SpravceZamestnancu
. Třída bude obsahovat kolekci zaměstnanců.
Kolekce bude typu DefaultListModel
, abychom ji později mohli
využít pro více zaměstnanců.
private final DefaultListModel<Zamestnanec> zamestnanci = new DefaultListModel<>();
Dále vytvoříme ve třídě čtyři metody: uloz()
,
nacti()
, vratPrvniho()
a ulozPrvniho()
.
Metody uloz()
a nacti()
budeme implementovat až v
následující lekci. Poslední dvě metody tu máme pouze pro jednoduchost,
abychom mohli pracovat s jedním zaměstnancem. Jejich implementace bude
následující:
public Zamestnanec vratPrvniho() { return zamestnanci.size() == 0 ? new Zamestnanec() : zamestnanci.get(0); } public void ulozPrvniho(Zamestnanec zamestnanec) { this.zamestnanci.clear(); this.zamestnanci.addElement(zamestnanec); }
Úprava formuláře
To by bylo prozatím ve správci vše. Přesuňme se ještě rychle do
formuláře, kde vytvoříme instanci správce a necháme si od něj instancovat
třídu Zamestnanec
:
private final SpravceZamestnancu spravce = new SpravceZamestnancu(); private Zamestnanec zamestnanec = spravce.vratPrvniho();
Dále do kódu formuláře přidáme dvě pomocné metody, pomocí kterých
budeme aktualizovat údaje na formuláři a v instanci třídy
Zamestnanec
:
private void aktulizujFormular() { jTxtName.setText(zamestnanec.getJmeno()); jTxtSurname.setText(zamestnanec.getPrijmeni()); jTxtEmail.setText(zamestnanec.getEmail()); jTxtPhoneNumber.setText(zamestnanec.getTelefon()); jTxtBirthday.setText(Konstanty.FORMAT_DATA.format(zamestnanec.getNarozeniny())); jPanel1.getGraphics().drawImage(zamestnanec.getObrazek(), 0, 0, 123, 135, null); } private void nactiZFormulare() { zamestnanec.setJmeno(jTxtName.getText()); zamestnanec.setPrijmeni(jTxtSurname.getText()); zamestnanec.setEmail(jTxtEmail.getText()); zamestnanec.setTelefon(jTxtPhoneNumber.getText()); zamestnanec.setNarozeniny(LocalDate.parse(jTxtBirthday.getText(), Konstanty.FORMAT_DATA)); }
Obsluha tlačítek
Nakonec se podíváme na handlery tlačítek.
Výběr obrázku
První handler, na který se zaměříme, je obsluha tlačítka pro výběr obrázku:
private void jBtnImageActionPerformed(java.awt.event.ActionEvent evt) { nactiZFormulare(); JFileChooser fileChooser = new JFileChooser(); fileChooser.setFileFilter(new FileNameExtensionFilter("Obrázky...", "png")); final int result = fileChooser.showOpenDialog(this); if (result == JFileChooser.APPROVE_OPTION) { final File obrazek = fileChooser.getSelectedFile(); try { zamestnanec.setObrazek(ImageIO.read(obrazek)); aktulizujFormular(); } catch (IOException e) { e.printStackTrace(); } } }
Nejdříve uložíme případné hodnoty z komponent do instance třídy
Zamestnanec
. Dále vytvoříme nový JFileChooser
dialog, pomocí kterého vybereme obrázek uživatele. Pokud obrázek vybereme
úspěšně, metodou ImageIO.read()
načteme obrázek a uložíme
ho do zaměstnance. Nakonec zavoláme metodu aktualizujFormular()
,
pomocí které zobrazíme obrázek na formuláři.
Uložení
Obsluha tlačítka pro uložení dat bude vypadat následovně:
private void jBtnSaveActionPerformed(java.awt.event.ActionEvent evt) { JFileChooser fileChooser = new JFileChooser(); fileChooser.setFileFilter(new FileNameExtensionFilter("Soubory zaměstnanců...", "zam")); final int result = fileChooser.showSaveDialog(this); if (result == JFileChooser.APPROVE_OPTION) { final File souborZamestnancu = fileChooser.getSelectedFile(); try { nactiZFormulare(); spravce.ulozPrvniho(zamestnanec); spravce.uloz(souborZamestnancu); } catch (IOException | XMLStreamException e) { e.printStackTrace(); } } }
Pomocí JFileChooser
dialogu vybereme soubor, do kterého chceme
uložit naše data. Pokud soubor vybereme, načteme data z formuláře do
instance zaměstnance. Tuto instanci předáme do správce, aby si uložil data.
Nakonec metodou uloz()
zapíšeme veškerá data do souboru.
Načtení
Nakonec si ukážeme metodu pro načtení dat:
private void jBtnLoadActionPerformed(java.awt.event.ActionEvent evt) { JFileChooser fileChooser = new JFileChooser(); fileChooser.setFileFilter(new FileNameExtensionFilter("Soubory zaměstnanců...", "zam")); final int result = fileChooser.showOpenDialog(this); if (result == JFileChooser.APPROVE_OPTION) { final File souborZamestnancu = fileChooser.getSelectedFile(); try { spravce.nacti(souborZamestnancu); zamestnanec = spravce.vratPrvniho(); aktulizujFormular(); } catch (IOException | ParserConfigurationException | SAXException e) { e.printStackTrace(); } } }
V metodě opět zobrazíme JFileChooser
dialog pro výběr
zaměstnanců. Pokud zvolíme soubor, zavoláme metodu nacti()
nad
instanci třídy SpravceZamestnancu
. Po úspěšném načtení
zobrazíme data prvního zaměstnance na formulář.
Nyní máme aplikaci navrženou.
V následujícím kvízu, Kvíz - Práce se soubory a složkami v Javě, si vyzkoušíme nabyté zkušenosti z předchozích lekcí.
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 63x (43.15 kB)
Aplikace je včetně zdrojových kódů v jazyce Java