Lekce 15 - Derby DB - Ukládání/Získání souborů
V minulé lekci, Derby DB - Ukládání/získání jednoduchých datových typu, jsme se věnovali ukládání různých primitivních typů.
V dnešním DerbyDB tutoriálu si probereme ukládání souborů. Je jedno, jaký typ souborů, jestli se jedná o soubory hudební (např. mp3, wav, ..), video (např. mkv, avi, ...), obrázky(např. jpg, gif, ...) nebo pouze soubory dat či spouštěcí soubory (např. txt, dat, xml, bin, exe, com, ...). DerbyDB podporuje 3 typy těchto souborů z celé SQL definice java.sql.Types. Nejdříve si promyslete, jaký soubor chcete do databáze ukládat, a pak mu přiřaďte jeden z podporovaných datových typů níže:
- BLOB (Binary Large OBject): Jedná se binární soubor s proměnnou velikostí o maximální velikosti 2,147 GB
- CLOB (Character Large OBject): Jedná se znakový soubor v UNICODE s proměnnou velikostí o maximální velikosti 2,147 GB
- XML (XML soubor): V DerbyDB práce s XML souborem není
přímo podporována. V JDBC existuje objekt SQLXML, který představuje náš
XML soubor. DerbyDB tento objekt nemá přímo (a tak jak by měl být)
implementovaný, takže vždy bude
null
, a při práci s ním se zavolá výjimka. Nejjednodušším řešením je využívat XML soubor jako CLOB. XML soubor je soubor znakový a tudíž CLOB je logická volba. Což znamená, že při tvorbě tabulky sloupec pro XML nastavíme jako CLOB. Nicméně existuje i možnost, jak XML soubor přes DerbyDB použít, a to přes XMLPARSE, ale je to poněkud zdlouhavější.
My se rozhodneme nevyužít variantu CLOB (definice sloupce v tabulce) při uchování XML v řešeném příkladu, ale zvolíme krkolomnější řešení XMLPARSE, které DerbyDB umožňuje. Při tvorbě tabulky definujeme sloupec jako XML. Problémem tohoto řešení je, že XML se do databáze uloží bez hlavičky (deklarace), což je zcela nevhodné. Ztratíme tak zásadní metainformace jako verze XML, kódování znakové sady a podobné, které k XML patří.
Vyřešíme to velmi jednoduše, samotnou deklaraci XML načteme jako
String
a tu uložíme do databáze také. Při získání XML
souboru z databáze pak pouze daný String
k XML souboru prostě a
jednoduše přidáme. Nejedná se o zcela nejvhodnější řešení, ale jako
příklad bohatě stačí. Zajisté si pak všimnete, že při zpracování XML
využíváme getter/setter pro CLOB. To je nevyhnutelné. Takže používání
XMLPARSE je prakticky zbytečné. CLOB funguje dobře a nemusíte řešit
problém s hlavičkou (deklarací) XML.
Datový typ Java | Syntaxe | Datový typ Derby | JDBC metatyp(java.sql.Types) | Poznámka |
---|---|---|---|---|
java.io.InputStream | InputStream | BLOB | viz. JAVA API | |
java.io.InputStream | InputStream | CLOB | viz. JAVA API | |
java.io.InputStream | InputStream | SQLXML | viz. JAVA API | Není plně podporován |
Tentokrát si nebudeme ukazovat ukládání souborů přes IJ, protože to snad ani nejde, možná přes nějaký komplikovanější skript.
Vytvoření tabulky programově jako uzivatel10 a naplnění tabulky daty
Vytvoříme si testovací příklad v Java SE projekt v IDE. V menu zvolíme File -> New -> Java Project. Pojmenujeme projekt a nastavíme JRE Java8. Přidáme opět externí knihovny do našeho projektu do CLASSPATH. Jedná se o tyto externí knihovny:
derbyclient.jar
derby.jar
derbytools.jar
derbyoptionaltools.jar

Jak vidíte, do projektu se přidaly nutné knihovny. Navíc jsem v projektu
vytvořil adresář vstupy/
, kam jsem nakopíroval vzorové
soubory. Konkrétně jeden obrázek, jeden XML soubor a jeden soubor zdrojového
kódu z Javy. Tyto soubory budeme ukládat do DerbyDB.

Kód je koncepčně prakticky stejný jako v minulém příkladě.
Přihlásíme se jako uzivatel10
a vytvoříme tabulku
Soubory
. Naplníme ji daty, vybereme data a uložíme do adresáře
výstupy/
. Všechny soubory budeme mít uloženy v objektu
InputStream
. Protože, jak jsem výše uvedl, XMLPARSE nenačte
hlavičku (deklaraci) XML souboru, tak ji uložíme (znakově načteme) do
StringBuilder
a převedeme do String
u a do databáze
ji uložíme jako VARCHAR
:
package datab; import java.io.*; import java.sql.*; public class Soubory { private static Connection connect = null; private static PreparedStatement statement = null; static { try { // nutne pridat do CLASSPATH - derbyclient.jar Class.forName("org.apache.derby.jdbc.ClientDriver").newInstance(); } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { System.out.println("Problem s nactenim driveru - nutne pridat do CLASSPATH - derbyclient.jar"); } } private static void pripojeniDatabaze(String jmeno, String heslo) { try { connect = DriverManager.getConnection("jdbc:derby:C:/Program Files/JavaJDK08/db/bin/databaze10;user=" + jmeno + ";password=" + heslo + ";"); System.out.println("Podarilo se pripojit k databazi10"); } catch (Exception e) { System.err.println("Nepodarilo se pripojit k databazi10"); if (connect == null) { System.exit(1); } } } private static void odpojimeDatabazi() { try { if (statement != null) { statement.close(); } if (connect != null) { connect.close(); } System.out.println("Podarilo se odpojit od databaze"); } catch (SQLException e) { e.printStackTrace(); } } private static void vytvoreniTabulky(String s) { try { statement = connect.prepareStatement("create table " + s + " (id INT not null primary key GENERATED ALWAYS AS IDENTITY(START WITH 1, INCREMENT BY 1), " + " obrazekBlob BLOB(200K),souborClob CLOB(1K), souborXML XML, deklaraceXML VARCHAR (4096) )"); statement.execute(); System.out.println("Podarilo se vytvorit tabulku : " + s); } catch (SQLException e) { System.out.println("Nepovedlo se vytvorit tabulku :"); e.printStackTrace(); } } private static void naplneniDatTabulky(String s) { InputStream obrazekStream = null, souborStream = null, xmlStream = null,xmlDeclaration = null; String deklaraceXML=null; try { File soubor = new File("vstupy\\textura.png"); obrazekStream = new FileInputStream(soubor); soubor = new File("vstupy\\CalculateFPSExample.java"); souborStream = new FileInputStream(soubor); soubor = new File("vstupy\\jidlo.xml"); xmlStream = new FileInputStream(soubor); xmlDeclaration = new FileInputStream(soubor); // ziskame deklaraci XML souboru do Stringu int ch; StringBuilder sb = new StringBuilder(); while((ch = xmlDeclaration.read()) != '>') sb.append((char)ch); deklaraceXML = sb.toString()+">"; System.out.println("Poradilo se nacist standardni soubory"); } catch (Exception e1) { System.out.println("Neporadilo se nacist standardni soubory"); e1.printStackTrace(); } // Ulozime datove typy try { statement = connect.prepareStatement("INSERT INTO " + s + "(obrazekBlob,souborClob,souborXML,deklaraceXML) " + "VALUES (?,?,XMLPARSE(DOCUMENT CAST(? AS CLOB) PRESERVE WHITESPACE),?)"); statement.setBinaryStream(1, obrazekStream); statement.setAsciiStream(2, souborStream); statement.setAsciiStream(3, xmlStream); statement.setString(4,deklaraceXML); statement.execute(); System.out.println("Podarilo se ulozit data"); } catch (SQLException e) { System.out.println("Nepovedlo se ulozit data"); e.printStackTrace(); } try { obrazekStream.close(); souborStream.close(); xmlStream.close(); System.out.println("Podarilo se ukoncit cteci streamy"); } catch (IOException e) { System.out.println("Nepodarilo se ukoncit cteci streamy"); e.printStackTrace(); } } private static void vyjmemeDataZTakulky(String s) throws Exception { File newfile = null; try { Statement statement = connect.createStatement(); ResultSet odpoved = statement.executeQuery("SELECT obrazekBlob,souborClob,XMLSERIALIZE(souborXML AS CLOB),deklaraceXML FROM " + s + " ORDER BY id"); System.out.println("Podarilo se ziskat data CLOB,BLOB "); while (odpoved.next()) { // BLOB - nacteme a vytvorime soubor byte[] buff = new byte[1024]; Blob ablob = odpoved.getBlob(1); newfile = new File("vystupy\\newBlob.jpg"); InputStream is = ablob.getBinaryStream(); FileOutputStream fos = new FileOutputStream(newfile); for (int b = is.read(buff); b != -1; b = is.read(buff)) { fos.write(buff, 0, b); } is.close(); fos.close(); // CLOB - nacteme a vytvorime soubor buff = new byte[1024]; Clob aclob = odpoved.getClob(2); newfile = new File("vystupy\\newClob.java"); is = aclob.getAsciiStream(); fos = new FileOutputStream(newfile); for (int b = is.read(buff); b != -1; b = is.read(buff)) { fos.write(buff, 0, b); } is.close(); fos.close(); System.out.println("Podarilo data ulozit do souboru CLOB,BLOB"); // XML - ziskame hlavicku XML ze stringu String deklaraceXML = odpoved.getString(4); InputStream stream = new ByteArrayInputStream(deklaraceXML.getBytes(java.nio.charset.StandardCharsets.UTF_8)); // XML - nacteme buff = new byte[1024]; aclob = odpoved.getClob(3); newfile = new File("vystupy\\newXML.xml"); is = aclob.getAsciiStream(); // prevedeme inpustream do xml souboru fos = new FileOutputStream(newfile); for (int b = stream.read(buff); b != -1; b = stream.read(buff)) { fos.write(buff, 0, b); } fos.write(System.getProperty("line.separator").getBytes()); for (int b = is.read(buff); b != -1; b = is.read(buff)) { fos.write(buff, 0, b); } is.close(); fos.close(); System.out.println("Podarilo data ulozit do souboru XML"); } odpoved.close(); System.out.println("Soubor se podarilo nacist - vznikl - vystupy/newBlob.jpg"); System.out.println("Soubor se podarilo nacist - vznikl - vystupy/newClob.java.java"); System.out.println("Soubor se podarilo nacist - vznikl - vystupy/newXML.xml"); } catch (SQLException e) { System.out.println("Nepovedlo se ziskat/ulozit data do souboru"); e.printStackTrace(); } } private static void smazemeTabulku(String s) { try { statement = connect.prepareStatement("DROP TABLE " + s); statement.execute(); System.out.println("Podarilo se smazat tabulku : " + s); } catch (SQLException e) { e.printStackTrace(); System.out.println("Nepodarilo se smazat tabulku : " + s); } } public static void main(String[] args) throws Exception { System.out.println("Start programu"); pripojeniDatabaze("uzivatel10", "heslo10"); vytvoreniTabulky("Soubory"); naplneniDatTabulky("Soubory"); vyjmemeDataZTakulky("Soubory"); smazemeTabulku("Soubory"); odpojimeDatabazi(); System.out.println("Konec programu"); } }
Protože XML soubor se skládá v databází ze dvou části, je nutno při
zápisu XML do souboru danou hlavičku do XML souboru vrátit. To provedeme
standardním zápisem přes FileOutputStream
přes pole
byte[]
. Protože je hlavička první, tak nejdříve do souboru
zapíšeme jako první. Pak provedeme zápis odřádkování no a poslední
provedeme zápis těla (body) našeho XML souboru.

Jak vidíte, kód proběhne bez chyby.
V následujícím kvízu, Kvíz - Jednoduché datové typy a soubory Derby DB 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 8x (271.1 kB)
Aplikace je včetně zdrojových kódů v jazyce Java