# ZipFile-Attribut aus byte-Array (ohne schreiben ins FileSystem)



## rex_05 (13. April 2010)

Hallo zusammen,

ich habe ein ZipFile als byte-Array in eine Datenbank geschrieben. Auch kann ich die Spalte der Tabelle wieder auslesen und bekomme den Content als byte-Array.

Jetzt bekomme ich es aber nicht hin, aus dem byte-Array wieder ein ZipFile (NICHT im Filesystem, sonern nur im Speicher, in meiner Klasse!) zu machen. (Bin halt nunmal noch kein Profi  )

Ziel des ganzen soll es sein, dass ich das File aus der DB auslese, dann als ZipFile-Objekt habe und dann z.B. einzelne Dateien inneralb des ZipFiles entpacken kann etc.

Meine Frage ist also: Wie bekomme ich aus einem byte-Array ein Objekt der Klasse ZipFile?

Eingelesen wird das File momentan so: (InputFile ist nur eine Bean in der ich das File zwischenspeicher.)

```
public InputFile readInputFile() {
		InputFile inputFile = new InputFile();
		try {
			inputFile.setFile(new File(inputFilePath));
			init();

			byte[] byteArray = new byte[(int) inputFile.getFile().length()];
			FileInputStream fileInputStream = new FileInputStream(inputFile
					.getFile());
			fileInputStream.read(byteArray);
			inputFile.setBytes(byteArray);
			fileInputStream.close();
...
```
Hier wird das File noch direkt von der Festplatte eingelesen.
Das hier gestezte byte-Array wird dann in die DB geschrieben.

Vielen Dank und Grüße
Sandro


----------



## Vereth (13. April 2010)

Dann mache dir einen _ZipInputStream_, mit dessen Hilfe du Zugriff auf die _ZipEntry_-Einträge bekommst. Als _InputStream_ für den Konstruktor verwendest du einen _ByteArrayInputStream_, den du aus deinem _byteArray _erzeugst. Das Ganze sieht dann beispielsweise so aus:

```
ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(byteArray));
```


----------



## Akeshihiro (13. April 2010)

Ich habe hier mal einen sehr interessanten Beitrag gefunden, ist zwar nicht der neuste, aber funktioniert ^^ klick
Das Entpacken ist also kein Problem ^^


----------



## rex_05 (13. April 2010)

Danke für die schnellen Antworten!

Ich habe es jetzt mit 

```
public void installUpdate(Serializable id) {
		Update update = genericDao.getById(Update.class, id);

		ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(update
				.getContent()));
		ZipEntry entry;
		try {
			while ((entry = zis.getNextEntry()) != null) {
				System.out.printf("%s%-54s   Size: %6d   Packed: %6d   %tc%n",
						entry.isDirectory() ? "+" : " ", entry.getName(), entry
								.getSize(), entry.getCompressedSize(), entry
								.getTime());
			}
```

hinbekommen das File aus der DB auszulesen und den Inhalt auzugeben. So wie ich es auch machen kann, wenn ich ein File direkt von der Platte einlese. Das hilft mir für das Erste schon einmal weiter! 

Aber ist es nicht möglich aus so einem Stream wieder ein ZipFile- bzw. File-Objekt wie

```
ZipFile file = new ZipFile("Pfad...");
file.size();
```

zu machen So dass ich einfach das ZipFile-Objekt als Parameter an andere Methoden übergeben, oder die Anzahl an Einträgen in dem File bekommen kann etc.
Dazu habe ich leider keine Info gefunden.

Bis jetzt müsste ich ja immer den ZipInputStream öffnen wenn ich an irgendeiner Stelle im Programm Zugriff auf das ZipFile benötige?! Oder habe ich da etwas nicht verstanden?

Nochmals Danke!


----------



## Akeshihiro (13. April 2010)

Mir ist keine Möglichkeit bekannt. Ich habe mir mal die Klasse ZipFile "diagonal" angeschaut und bin zu dem Entschluss gekommen, dass es dafür eine File-Referenz geben muss. Es werden auch diverse native Methoden zum Bearbeiten und Auslesen des Archives verwendet und diese beziehen sich scheinbar auf Dateien, die auch vorhanden sein müssen. Also mir fällt so keine Möglichkeit ein, wie man ZipFile ohne File erzeugen kann.

Warum willst du den Umgang mit Dateien eigentlich meiden? Du kannst doch auch temporäre Dateien erstellen und mit diesen arbeiten  Dabei können dir die Methoden createTempFile() und deleteOnExit() helfen ...


----------



## Vereth (13. April 2010)

Das Schreiben in eine Datei funktioniert genauso, nur andersrum.

```
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream("Pfad/Dateiname.zip"));
zos.putNextEntry(deinZipEntry);
```


----------



## rex_05 (13. April 2010)

Nochmals Danke.
Dann muss ich es halt irgendwie anders hin bekommen.

PS: Das ENtpacken nach klick funktioniert bei mir nicht. (Das System kann den angegebenen Pfad nicht finden) Liegt wohl an der Ordnerstruktur in meinem ZipFile. Vielleicht fällt mir da heute Abend noch etwas ein. Wenn ich nur eine Einzelne Datei im zipFile liegen habe geht es.

Wie schon einmal gesagt
Danke
---------------------------------------------------------------------------------

Um die Frage zu klären was ich überhaupt machen will:
Ich habe eine WebAnwendung (JSF2.0 Spring3, Hibernate, jBPM, PostgteSQL) und möchte auf Knopfdruck neue Prozesse für jBPM (Prozessdefinition + Formulare + Java Class-Dateien) ins System laden.
Dazu will ich alle benötigten Dateien in eine Zip-Datei packen, die dann so aussehen könnte:

```
+forms/                                                   Size:      0   Packed:      0   Fr Apr 09 13:30:42 MESZ 2010
 forms/entscheidungCheff.xhtml                            Size:   1689   Packed:    703   Fr Apr 09 11:27:14 MESZ 2010
 forms/start.xhtml                                        Size:   1033   Packed:    508   Fr Apr 09 11:00:10 MESZ 2010
 forms/ueberGegenvorschlagEntscheiden.xhtml               Size:   1626   Packed:    701   Fr Apr 09 11:42:38 MESZ 2010
+src/                                                     Size:      0   Packed:      0   Fr Apr 09 13:29:24 MESZ 2010
 src/gehaltsverhandlung.jpdl.xml                          Size:   2810   Packed:    782   Fr Apr 09 11:41:46 MESZ 2010
 src/gehaltsverhandlung.png                               Size:   3715   Packed:    719   Fr Apr 09 11:41:46 MESZ 2010
+src/handler/                                             Size:      0   Packed:      0   Fr Apr 09 13:29:04 MESZ 2010
 src/handler/AssignTask.java                              Size:    787   Packed:    401   Fr Apr 09 11:04:46 MESZ 2010
 src/handler/Init.java                                    Size:    767   Packed:    399   Fr Apr 09 10:10:26 MESZ 2010
 src/handler/setForderung.java                            Size:    727   Packed:    380   Fr Apr 09 10:19:42 MESZ 2010
```
Die Anzahl der Dateien kann variieren. (Die .java Dateien nachher natürlich als .class, ist ja jetzt nur zum Testen)

Auf Knopfdruck soll dann eben der Inhalt von "forms/" nach WebContent/pages/updates/"name des zipFiles" kopiert werden.
Analog dazu der Inhalt von "/src" eben in den Ordner für die Class-Dateien.

Wenn ich irgendwann einmal so weit bin, kommt die nächste Herausvorderung, nämlich das Auffinden von allen Dateien in der WebApp mit der Endung ".jpdl.xml" Um diese dann jBPM zugänglich zu machen.
Alternativ dazu könnte man aber auch direkt beim Entpacken alle Dateien mit .jpdl.cml" in ein eigenes Verzeichnis entpacken. Wobei ich eher zur ersten Variante tendiere, da man auch auf Knopfdruck ein einmal eingespieltes Update wieder komplett löschen können soll.

So ganz sicher bin ich mir auch noch nicht, wie ich das alles anstellen soll. 
Aber was tut man nicht alles für sein Studium.


----------



## Kai008 (13. April 2010)

Die Exception hängt wohl eher damit zusammen, dass der Ordner, in dem du schreiben willst (noch) nicht existiert.
file.mkdirs().


----------



## Akeshihiro (13. April 2010)

Also bei mir hatte das super funktioniert. Ich musste natürlich prüfen, ob ich ein Verzeichnis entpacken will, aber sonst alles easy going gewesen ...

Hier mal mein Code:

```
public class Main {
	public static void main(String[] args) throws IOException {
		File f = new File("/home/link/test.zip");

		// Array, das ein Zip-Archiv in Bytes beinhaltet
		byte[] bytesFromZip = new byte[(int)f.length()];

		// ZipArchiv einlesen
		BufferedInputStream bis = new BufferedInputStream(
				new FileInputStream(f));
		bis.read(bytesFromZip);
		bis.close();

		/*
		 * Hier wirds interessant. Man kann via ByteArrayStreams auf das
		 * Byte-Array zugreifen und dann den Zip-Inhalt via ZipInputStream
		 * einlesen ...
		 */
		List<ZipEntry> entries = new LinkedList<ZipEntry>();
		ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(
				bytesFromZip));
		for(ZipEntry entry = null; (entry = zis.getNextEntry()) != null;) {
			entries.add(entry);
		}
		// zis.close();

		// Allein Einträge mit Namen ausgeben (Test, obs geklappt hat)
		for(ZipEntry e : entries) {
			System.out.println(e.getName());
		}

		// Einträge entpacken
		for(ZipEntry e : entries) {
			File newFile = new File("/home/link/test/", e.getName());
			if(e.isDirectory()) {
				newFile.mkdir();
				continue;
			}

			BufferedOutputStream bos = new BufferedOutputStream(
					new FileOutputStream(newFile));
			for(int c = -1; (c = zis.read()) != -1;) {
				bos.write(c);
			}
			bos.flush();
			bos.close();
		}
		
		// Und den Zip-Stream schließen
		zis.close();
	}
}
```
Ist natürlich nur provisorisch, so würde ich das natürlich nicht produktiv verwenden sondern diverse Klassen dafür zurechtbasteln. Aber war ja auch nur zum Testen da ^^


----------



## Vereth (13. April 2010)

Kleine Schönheitskorrektur: Die Variable c brauchst du nicht zu initialisieren, sie wird beim Abarbeiten der Schleifenbedingung früh genug gesetzt. Eine while-Schleife genügt also.


```
int c; while((c = zis.read()) != -1) {
```


----------



## Akeshihiro (13. April 2010)

Das Problem ist, dass bei dir die Variable c auch nach der Schleife existiert und das versuche ich zu vermeiden, indem ich Variablen, deren Sinn und Zweck nur so eine einmalige Aktion bezweckt, auch nur dafür ins Leben zu rufen. Nach der Schleife ist meine Variable weg und kann nicht mehr missbraucht werden


----------



## Vereth (13. April 2010)

Wenn das deine Motivation ist, dann spare dir die Variable doch ganz.

```
while ( zis.available() != 0 ) 
{ bos.write(zis.read()); }
```


----------



## Akeshihiro (13. April 2010)

Stimmt, das ist sogar noch besser ^^ Danke ^^


----------

