Ordner mit zip komprimieren

Hi.

Ich sitz hier seit 2 Tagen an einem Problem, habe das java-forum, byte-welt, zwei bücher durch geschaut und gegoogelt, und ich bekomme den Fehler einfach nicht heraus.

Und zwar geht es darum, einen Ordner zu über ZipOutputStream zu verfahren. Die Dateien werden rekursiv durchlaufen und einfach als ZipEntry dann dem Archiv hinzugefügt. Nur, funktionieren tut das nicht :smiley: Die kompromierte Datei wird erzeugt, es befindet sich aber nur 1 Datei darin, mit der Ordnerstruktur für diese Datei. Mal ist die Datei richtig geschrieben, manchmal ist sie leer. Inzwischen ist sie aber glaube ich immer leer.

Das ganze sieht so aus bei mir:

Einsprungspunk ist pack, der Parameter file ist ein Ordner der alle anderen Ordner und Dateien erhält.

		try {
			zipOutput = new ZipOutputStream(new FileOutputStream(destination));
			output = new BufferedOutputStream(zipOutput);
			if (file.isDirectory()) {
				compress(file);
				for (File files : file.listFiles()) {
					pack(files, destination);
				}
			} else {
				compress(file);
			}
			output.close();
			zipOutput.close();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
	}
	
	void compress (File file) {
		if (file != null) {		
			if (!file.isDirectory()) {
				try {
					zipOutput.putNextEntry(new ZipEntry(getArchiveFileName(file)));
					BufferedInputStream input = new BufferedInputStream(new FileInputStream(file));
					byte[] buffer = new byte[8190];
					int length;
					while ((length = input.read(buffer)) != -1) {
						output.write(buffer, 0, length);
						output.flush();
					}
					zipOutput.closeEntry();
					input.close();
				} catch (FileNotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} 			
			} else if (file.isDirectory()) {
				try {
					zipOutput.putNextEntry(new ZipEntry(getArchiveFileName(file)+"/"));
					zipOutput.closeEntry();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		} else {
			//TODO error
		}
	}
	
	private String getArchiveFileName(File file) {
		String filePath = file.getAbsolutePath();
		int index = filePath.indexOf(nameToken);
		return filePath.substring(index);
	}```

Wie gesagt, ich habe keine Idee.

Hätte da jemand eine Idee?^^

Danke, schonmal im voraus.

Grüße
Morgyr


Edit: Der BufferedOutputStream wird inzwischen dann auch mal wieder geschlossen und vor Allem auch geflushed. Somit ist die einzige Datei, die komprimiert wird, auch wirklich komplett.

Hi,

ich hab mirs nicht im Detail angeschaut, aber vermutlich ist das Problem, dass jedesmal (in jeder Rekursionsstufe) ein neuer ZipOutputStream und ein neuer OutputStream aufgemacht wird.

Noch ein paar generelle Anmerkungen:

  • du solltest deinen Code-Stil überdenken (protected, public oder private Zugriffsmodifizierer für die Methoden verwenden). Sonst könnte man die compress Methode von außen aufrufen, was gleich zu einem Fehler führt, weil die globalen Objekte null sind.
  • die letzte Methode getArchiveFileName kapiert auf den ersten Blick niemand. Da würde eine Zeile Kommentar schon viel helfen ^^. Ich glaube, dass man sich die Methode übrigens schenken kann und mit file.getName() abkürzen kann…
  • ich glaube es wäre geschickter, keine globalen Variablen (output Stream) zu verwenden, sondern diese als Parameter im Methodenaufruf mitzugeben. In der Methode werden die dann auf null geprüft und wenn sie null sind muss man sie halt erzeugen (-> im Kommentar erwähnen)
  • Hier gibt es Redundanz:
                compress(file);
                for (File files : file.listFiles()) {
                    pack(files, destination);
                }
            } else {
                compress(file);
            }```
kann man abkürzen durch:

```compress(file);
if (file.isDirectory()) {
                for (File files : file.listFiles()) {
                    pack(files, destination);
                }
            ```


Wenn du es nicht zum laufen bekommst melde dich einfach, dann kann ich dir das notfalls auch coden. Generell lohnt es sich aber (gerade am Anfang) ruhig einige Tage an so nem Problem rumzuknabbern. Das ist zwar nervig, aber man lernt viel dabei ;)

Gruß Revenant

Hi.

Sowas blödes -.- Da vermischt man mehre Ideen miteinander und erzeugt wird ein Wirrwarr. Danke :smiley: genau das war das Problem.

Zu den anderen Tipps:

  1. Der package-protected ist im Grunde so bewusst gewählt. pack() darf nur innerhalb des Packages aufgerufen werden. Oder gilt das in den Code Conventions als „Unding“? Dass compress aber private sein muss, ist richtig. Solche Fehler kommen bei mir immer erst, wenn der Code läuft, vorher achte ich auf sowas auch nicht :smiley:
  2. Kommentare fehlen da sicherlich. Das kommt aber auch schon fast wieder unter den Punkt den ich in Punkt 1 angesprochen habe. Ansonsten: file.getName() liefert doch immer nur den letzten Teil des Pfades zurück. Bspw. „C:\Example est.txt“, getName() würde hier test.txt zurückgeben. Wenn ich jetzt aber den Ordner Example komprimieren will, dann brauch mehr als nur „test.txt“, um die Struktur auch nach einem Entpacken wieder zu haben. Sehe ich zumindest so, aber sollte das Missverständniss, wenn es eins ist, durch fehlende Kommentare kommen, sorry.
  3. Ja. Da hast du wohl recht. Ich habe das mal geändert. Danke.
  4. Auch hier hast du recht :stuck_out_tongue: Aber das passt wohl wieder in die in Punkt 1 angesprochene Kategorie von Aufgaben^^

dann kann ich dir das notfalls auch coden

Das käme nur in Frage, wenn ich wirklich mehrere tagelang keinen Schritt vorwärts kommen würde. Aber danke für das Angebot :smiley:

Ansonsten, nochmal Danke :smiley:

Grüße,
Morgyr

Das ist jetzt sicherlich ne Philosophie Sache :), aber mein Chef hat mir immer geraten meine Methoden eher protected als private oder „default“ zu machen, damit bei späteren Erweiterungen der Klasse die Methoden vererbt werden können. Bei „default“ hat man natürlich einen sehr restriktiven Ansatz, der Erweiterungen einschränkt oder Änderungen der API/ Schnittstelle notwendig macht (!). Aber da scheiden sich letztendlich die Geister :wink:

Gruß Rev