IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
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 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
Nastavení Projektu - Derby DB

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.

Projekt - Derby DB

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 Stringu 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.

Provedeno - Derby DB

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

 

Předchozí článek
Derby DB - Ukládání/získání jednoduchých datových typu
Všechny články v sekci
Derby DB
Přeskočit článek
(nedoporučujeme)
Kvíz - Jednoduché datové typy a soubory Derby DB v Javě
Článek pro vás napsal Robert Michalovič
Avatar
Uživatelské hodnocení:
1 hlasů
Programuji převážně v Javě SE,EE a trochu nativním C a CUDA. více viz.https://cz.linkedin.com/in/robert-michalovic
Aktivity