# Schnellste Methode Datei aus Datenbank herstellen



## skizZ (9. Sep 2010)

Hallo zusammen,

ich bin gerade dabei Dateien in eine PostgreSQL  Datenbank zu speichern und danach wieder auszulesen und als Datei herzustellen.

Als Feldtyp habe ich in der Datenbank "bytea" genommen und füge die Dateien per JDBC folgendermaßen in die Datenbank ein:


```
FileInputStream fis = new FileInputStream(allFiles[i]);
PreparedStatement ps = c.prepareStatement("INSERT INTO files (name, file) VALUES (?, ?)", Statement.RETURN_GENERATED_KEYS);
ps.setString(1, allFiles[i].getName());
ps.setBinaryStream(2, fis, (int)allFiles[i].length());
ps.executeUpdate();
```

Somit habe ich die Datei im Binärformat in der Datenbank vorliegen.
Was ist nun die schnellste Methode die Datei wieder auf der Festplatte herzustellen?

Im Moment mache ich es so:


```
File f = new File("c:/test/" + rs.getString(2));
                        try {
                            f.createNewFile();
                        } catch (IOException ex) {
                            Logger.getLogger(Receiver.class.getName()).log(Level.SEVERE, null, ex);
                        }
                        int read = 0;
                        OutputStream out = null;
                        try {
                            out = new FileOutputStream(f);
                        } catch (FileNotFoundException ex) {
                            Logger.getLogger(Receiver.class.getName()).log(Level.SEVERE, null, ex);
                        }
                        InputStream is = rs.getBinaryStream(3); // to download
                        BufferedInputStream input = new BufferedInputStream(is);
                        while ((read = input.read()) != -1) {
                            out.write(read);
                        }
                        out.flush();
                        out.close();
```

Dies dauert bei 700 Dateien mit jeweils ca 20kb ca. eine Minute.
Hat jemand eine schnellere Lösung parat?


Viele Grüße
skizZ


----------



## madboy (9. Sep 2010)

```
InputStream is = rs.getBinaryStream(3); // to download
                        BufferedInputStream input = new BufferedInputStream(is);
                        while ((read = input.read()) != -1) {
                            out.write(read);
                        }
                        out.flush();
                        out.close();
```
Du liest jedes Byte einzeln und schreibst es auch einzeln. Verwende ein Array für's lesen und Schreiben:

```
byte[] data = new byte[1024];
while (input.read(data) != -1) {
   out.write(data);
```
Das wird so nicht ganz funktionieren, da auch am Ende noch das komplette Array geschrieben wird, obwohl nur halb voll, also noch anpassen vor Verwendung.


----------



## skizZ (9. Sep 2010)

Hallo,

genau sowas wollte ich vermeiden, da die Dateien im Endeffekt eine unbekannte Größe haben, also evtl muss das byte[] größer als 1024 sein... Wie vermeide ich, dass das komplette Array geschrieben wird? Solange schreiben bis byte[n] = null oder empty?


----------



## SlaterB (9. Sep 2010)

das steht doch überall, einfach nur ein einziges Beispiel anschauen bevor du das selber programmierst,
so schwer?

FileOutputStream : FileOutputStreamFileJava Tutorial


```
byte[] readData = new byte[1024];
      FileInputStream fis = new FileInputStream(originFile);
      FileOutputStream fos = new FileOutputStream(destinationFile);
      int i = fis.read(readData);

      while (i != -1) {
        fos.write(readData, 0, i); // hier wird gegebenenfalls nur ein Teil des Arrays geschrieben
        i = fis.read(readData);
      }
```

--------

extremer Tuning-Tipp:
byte[] > 20k

und evtl. zwei verschiedene Threads, einer liest aus der DB, ein anderer schreibt,
so werden die Pausen, in denen die DB für sich beschäftigt ist, auch gleichzeitig für Java genutzt,
falls DB auf anderen Rechner oder mehrere Rechenkerne vorhanden sind und genutzt werden

kann aber sein, dass das gar nichts bringt oder durch die Verwaltung mehrerer Threads alles noch länger dauert als vorher


----------



## Sekundentakt (9. Sep 2010)

Falls Du mehrere Festplatten parallel verwenden kannst, kannst Du auch mehrere schreibende Threads einsetzen, sofern diese auf verschiedene Platten schreiben.

Falls Du eine SSD verwendest, kannst Du - korrigiert mich, wenn ich falsch liege - sogar parallel mit verschiedenen Threads auf die selbe Festplatte schreiben. 

Je nach Hardware-Ausstattung gibt's also verschiedene Möglichkeiten, die Software anzupassen. Es existiert keine echte One-Size-Fits-All.

Aber mal aus Neugier: Warum speicherst Du die Datei überhaupt in einer Datenbank? Datenbanken sind in der Regel nicht dafür gemacht worden, Dateien zu speichern. Sinnvoller wäre es, den Pfad zur Datei in der DB vorzuhalten und die Datei dann über den angegebenen Pfad zu erfragen. Das schont zusätzlich Deine Ressourcen.

Ergänzend zu SlaterB's Link Tuning Java I/O Performance


----------



## skizZ (10. Sep 2010)

Ich danke euch. Aus einer Minute sind 7 Sekunden geworden.

lg
skizZ


----------



## Sekundentakt (10. Sep 2010)

Magst Du das Ergebnis nicht auch noch mal posten? 
Falls jemand ein ähnliches Problem hat, kann er sich dann anschauen, wie Du das gelöst hast.


----------



## SlaterB (10. Sep 2010)

das kommt bestimmt alles vom byteweisen Schreiben hin zu byte[]


----------

