zippen mit struktur?!


chrisdu

Grünschnabel
hallo zusammen,

habe bereits über

using ICSharpCode.SharpZipLib.Checksums;
using ICSharpCode.SharpZipLib.Zip;
using ICSharpCode.SharpZipLib.GZip;

in c# gezipped...

nun möchte ich allerdings einen kompletten ordner incl. dessen unterordner und dateien zippen und diese struktur auch später wieder in meinem zip file wiederfinden, jemand ne ahnung wie das geht...?

danke im voraus

chris
 

Alexander Schuc

crazy-weasel
Hallo.

Ich löse das wie folgt:

Code:
private void btnZip_Click(object sender, System.EventArgs e)
{
	ZipOutputStream s = new ZipOutputStream(File.Create(@"C:\testzip.zip"));
	s.SetLevel(1);
	DirectoryInfo maindir = new DirectoryInfo(txtPath.Text);
	parentPath = maindir.Parent.FullName + @"\";
	MessageBox.Show(parentPath);

	GoSubdirs(ref s,this.txtPath.Text);

	s.Close();
	lblMessage.Text = "done";
}

private void GoSubdirs(ref ZipOutputStream s, string path)
{
	DirectoryInfo dir = new DirectoryInfo(path);
	foreach (DirectoryInfo subdir in dir.GetDirectories())
	{
		GoSubdirs(ref s, subdir.FullName);
	}
	foreach (FileInfo fi in dir.GetFiles())
	{
		FileStream fs = File.OpenRead(fi.FullName);
			
		byte[] buffer = new byte[fs.Length];
		fs.Read(buffer, 0, buffer.Length);
		ZipEntry entry = new ZipEntry(dir.FullName.Replace(parentPath,"") + "/" + fi.Name);
		entry.Size = fs.Length;
		fs.Close();
		s.PutNextEntry(entry);
		s.Write(buffer, 0, buffer.Length);
	}
}
Im Textfeld txtPath steht der Pfad zum Verzeichniss das gepackt werden soll, in der Variable parentPath steht der Pfad in dem sich das zu packende Verzeichniss befindet.
Das benutze ich dann beim Erstellen des ZipEntries um vom vollen Namen mit dem ganzen Pfad nur den relativen Pfad zu erhalten.
Beim relativen Pfad erkennt er dann automatisch die Verzichnisse.

Mfg,
Alex
 

vbler22

Grünschnabel
Hallo,

nach einigen Anpassungen habe ich das Programm zum laufen bekommen. Kannst du mir noch ein Beispiel geben, mit dem ich die Dateien wieder entpacke ? Die beigelegten Beispiele können keine ZIP Dateien entpacken, wenn sie Unterordner enthalten.
 

Alexander Schuc

crazy-weasel
Hi.

Hier ein Snippet wie ich entpacke. Habs gleich aus einem meiner Programme kopiert.

Code:
using IO = System.IO;
...
string output_dir = IO.Path.GetDirectoryName(file);

using (ZipInputStream z_input = new ZipInputStream(new IO.FileStream(file,IO.FileMode.Open)))
{

	ZipEntry zipee;
	while ((zipee = z_input.GetNextEntry())!= null)
	{
		string dir_name		= IO.Path.GetDirectoryName(zipee.Name);
		string file_name	= IO.Path.GetFileName(zipee.Name);
		dir_name = System.IO.Path.Combine(output_dir, dir_name);

		IO.Directory.CreateDirectory(dir_name);

		if (!file_name.Equals(string.Empty))
		{
			using (IO.FileStream writer = IO.File.Create(IO.Path.Combine(dir_name, file_name)))
			{
				int size = 2048;
				byte[] data = new byte[2048];
				while (true) 
				{
					size = z_input.Read(data, 0, data.Length);
					if (size > 0) 
						writer.Write(data, 0, size);
					else 
						break;
				}
			}
		}	
	}

	z_input.Close();
}
Ich hoff der Code ist dir verständlich.

Lg,
Alex
 

vbler22

Grünschnabel
Hallo,

ich habe den Code jetzt so geändert, damit er in VB läuft.
Das entpacken der Unterordnerfunktioniert jetzt. Die Dateien haben aber nach dem entpacken alle eine Größe von 0 Byte.

Code:
    Public Sub ZipEntpacken(ByVal strQuellzip, ByVal strZiel)

        Dim z_input As ZipInputStream = New ZipInputStream(New IO.FileStream(strQuellzip, IO.FileMode.Open))
        Try
            Dim zipee As ZipEntry
            Do While 1
                zipee = z_input.GetNextEntry

                If zipee Is Nothing Then Exit Do

                Dim dir_name As String = IO.Path.GetDirectoryName(zipee.Name)
                Dim file_name As String = IO.Path.GetFileName(zipee.Name)
                dir_name = System.IO.Path.Combine(strZiel, dir_name)
                IO.Directory.CreateDirectory(dir_name)
                If Not file_name.Equals(String.Empty) Then

                    Dim writer As IO.FileStream = IO.File.Create(IO.Path.Combine(dir_name, file_name))
                    Try
                        Dim size As Integer = 2048
                        Dim data(2048) As Byte
                        While file_name.Equals(String.Empty) 'True
                            size = z_input.Read(data, 0, data.Length)
                            If size > 0 Then
                                writer.Write(data, 0, size)
                            Else
                                ' break
                            End If
                        End While
                    Finally
                        CType(writer, IDisposable).Dispose()
                    End Try
                End If
            Loop
            z_input.Close()

        Finally
            CType(z_input, IDisposable).Dispose()
        End Try
Edit von Alex S.: Bitte Code-Tags verwenden
 

Alexander Schuc

crazy-weasel
Hi.

Code:
While file_name.Equals(String.Empty) 'True
  size = z_input.Read(data, 0, data.Length)
  If size > 0 Then
    writer.Write(data, 0, size)
  Else
     ' break
  End If
End While
Hier wird der Fehler liegen.
file_name.Equals(String.Empty) liefert in dem Fall ja false

Code:
Do While True
  size = z_input.Read(data, 0, data.Length)
  If size > 0 Then
    writer.Write(data, 0, size)
  Else
     Exit Do' break
  End If
Loop
Das sollte klappen, wenn der VB.net Code lauffähig ist. Bin die Syntax nicht wirklich gewöhnt.
 

vbler22

Grünschnabel
Der Code funktioniert jetzt. In der Schleife fehlte ein Exit Do. Der Übersetzer konnte das break; wohl nicht umwandeln und hat es auskeklammert.

Soweit läuft das Programm jetzt. Die exe Dateien laufen nach dem entpacken wieder. Probleme habe ich aber bei Textdateien die z.B. folgenden Text enthält:

nvWHBxBUM7SBWTwYiN9TOkPL1Jj+a6KoEqBN2RrvOEouf2lBa28z1Y7X/GGBpVXhGoUHKH13ignRC+psVJsCi3m4LptP35oBinCFHuFSNafxf4TgfwnzQTM4Z3JrKDzz3uISHYgECv5kAa76ttglsCHedZNnTBC6zosEuy6K6l8Xp4FTctWlA9Hlet+5ymhehCAJiIY+VJ5BtnxVWSg2xKAv+hZCukuHPUGINw5diRo=

236 Byte.

Nach dem Entpacken hat sie am Ende ein Leerzeichen, ist 237 Byte groß. Dadurch ist sie nicht mehr brauchbar. Ist das jetzt ein Fehler in der Ziplib, oder mache ich etwas falsch ?

Den Originalcode habe ich nicht hinbekommen, ich habe den Packer so verändert:
Ich möchte nicht den Hauptordner mitpacken, sondern nur die Unterordner und die enthaltenen Dateien.



Code:
Dim strHauptpfad As String = Application.StartupPath + strTZ + "Programmdateien\"

        Dim s As ZipOutputStream = New ZipOutputStream(File.Create("monoinstaller.zip"))
        s.SetLevel(9)

        Dim maindir As DirectoryInfo = New DirectoryInfo(strHauptpfad)
        Dim parentPath As String = maindir.ToString

        GoSubdirs(s, parentPath, strHauptpfad)

        s.Close()
        MessageBox.Show("Fertig")
Code:
Private Sub GoSubdirs(ByRef s As ZipOutputStream, ByVal path As String, ByVal strHauptpfad As String)
        Dim dir As DirectoryInfo = New DirectoryInfo(path)
        Dim subdir As DirectoryInfo
        For Each subdir In dir.GetDirectories()
            GoSubdirs(s, subdir.FullName, strHauptpfad)
        Next
        Dim fi As FileInfo
        For Each fi In dir.GetFiles()
            Dim fs As FileStream = File.OpenRead(fi.FullName)

            ' im Normalfall allokiert man die Buffer im voraus
            ' hier aus Klarheitsgründen pro Datei einmal
            Dim buffer() As Byte = New Byte(fs.Length) {}
            fs.Read(buffer, 0, buffer.Length)

            ' und jetzt schreiben wir einen ZipEntry & die Daten      

            Dim a As String = dir.FullName.Replace(strHauptpfad, "")
            If a <> "" Then
                a = a + "\"     'Wenn Datei in einem Ordner ist
            Else
                'Normale Datei im Hauptverzeichnis
            End If

            Dim enTry As ZipEntry = New ZipEntry(a + fi.Name)
            s.PutNextEntry(enTry)
            s.Write(buffer, 0, buffer.Length)
        Next fi

    End Sub
 

Asterix-Ac

Erfahrenes Mitglied
Hallo Leute,

nun habe ich es geschafft, komplette Ordnerstrukturen zu zippen - Dank des Beitrages von Alex. Doch den Einpack-Vorgang möchte ich doch noch etwas korrigieren :
Alex wandelt die absoluten Pfade in relative um. Das geht so lange gut, bis man auf die Root-Ebene stösst und dort einen Ordner komprimieren möchte. Beispiel : C:\Ordner
Dieser wird nicht relativiert.
Die Relativierung erfolgt in der Methode 'GoSubdirs' direkt im Argument vom neuen ZipEntry:
Code:
ZipEntry entry = new ZipEntry(dir.FullName.Replace(parentPath,"") + "/" + fi.Name);
Ersetzt diese Zeile mit den folgenden:
Code:
string relativPath = ZipEntry.CleanName(dir.FullName.Replace(parentPath,"") + "/" + fi.Name);
ZipEntry entry = new ZipEntry(relativPath);
Nun werden auch die Odner in den Rootverzeichnissen relativiert.

Gruß,
Asterix
 

ecp

Grünschnabel
Hey Leute!

Bin halbwegs neu in C# und hab davor schon Ewigkeiten nicht mehr programmiert!
Hier meine Frage: Habe den Code von Alex jetzt auch in mein Programm implementiert, jedoch bekomme ich immer den Fehler "Der Name "GoSubdirs" ist im aktuellen Kontext nicht vorhanden!".

Was könnte ich vergessen oder Falsch gemacht haben

Mfg ECP
 

ForceDragonX

Grünschnabel
@Alexander Schuc: Deine Snippets sind wirklich genial. :)
Ich verwende bisher nur das erste Snippet (ich mache gerne alles nacheinander, das zweite Snippet kommt erst, wenn das folgende Problem gelöst ist).
Nun kann ich allerdings keinen Fortschritt mithilfe eines Backgroundworkers aus dem DoWork()-Event holen, da die eigentliche Arbeit in GoSubDirs erfolgt.
Wie mache ich denn, dass ich den Fortschritt dieses Events anzeigen lassen kann, oder den Gesamtfortschritt beider Events?
 

…•xXCecilXx•…

Grünschnabel
Hallo Tutorials Team,
Ich möchte den Thread hier gerne fortsetzen und zwar deshalb weil ich hier zwar C# beim Lösen des Zippens und entzippens finde aber das von mir benötigte VB leider nur im entzippen.
Deshalb bitte ich euch mir evtl. das was Alex in C# gepostet hat mir irgentwie in VB.NET zuzeigen ich habe es mal versucht(werde es auch weiter versuchen) den Code umzuschreiben aber die fehlermeldungen werden irgentwie nicht kleiner (ks nur die ausgabe der Fehler nicht sofortige Rote meldungen das es garnicht erst anläuft ;P)
wäre wirklcih sehr dankbar

hier mal mein ehm Brei den ich aus dem C# von Alex geschaffen habe
Code:
Imports ICSharpCode.SharpZipLib.Zip
Imports ICSharpCode.SharpZipLib.Core
Imports System.IO

Dim parentPath As String

Private Sub btnZip_Click() 'object sender, System.EventArgs e)
        Dim s As New ZipOutputStream(File.Create(TextBox2.Text))
        s.SetLevel(1)
        Dim maindir As New DirectoryInfo(TextBox1.Text)
        parentPath = maindir.Parent.FullName + "\"
        MessageBox.Show(parentPath)
        GoSubdirs(s, TextBox1.Text)
        s.Close()
    End Sub

    Private Sub GoSubdirs(ByVal s As ZipOutputStream, ByVal path As String)
        Dim Dir As New DirectoryInfo(path)
        For Each subdir In Dir.GetDirectories()
            GoSubdirs(s, subdir.FullName)
        Next
        Dim fi As FileInfo
        For Each fi In Dir.GetFiles()
            Dim fs As FileStream = File.OpenRead(fi.FullName)
            Dim buffer(fs.Length) As Byte
            fs.Read(Buffer, 0, Buffer.Length)
            Dim entry As New ZipEntry(Dir.FullName.Replace(parentPath, "") + "/" + fi.Name)
            entry.Size = fs.Length
            fs.Close()
            s.PutNextEntry(entry)
            s.Write(Buffer, 0, Buffer.Length)
        Next
    End Sub
ich hoffe mal das dies etwas hilft.
MfG Cecil
 

Peter86

Erfahrenes Mitglied
Code:
Imports ICSharpCode.SharpZipLib.Zip
Imports ICSharpCode.SharpZipLib.Core
Imports System.IO

Dim parentPath As String

Private Sub btnZip_Click() 'object sender, System.EventArgs e)
        Dim s As New ZipOutputStream(File.Create(TextBox2.Text))
        s.SetLevel(1)
        Dim maindir As New DirectoryInfo(TextBox1.Text)
        parentPath = maindir.Parent.FullName + "\"
        MessageBox.Show(parentPath)
        GoSubdirs(s, TextBox1.Text)
        s.Close()
    End Sub

    Private Sub GoSubdirs(ByVal s As ZipOutputStream, ByVal path As String)
        Dim Dir As New DirectoryInfo(path)
        For Each subdir In Dir.GetDirectories()
            GoSubdirs(s, subdir.FullName)
        Next
        Dim fi As FileInfo
        For Each fi In Dir.GetFiles()
            Dim fs As FileStream = File.OpenRead(fi.FullName)
            Dim buffer(fs.Length) As Byte
            fs.Read(Buffer, 0, Buffer.Length)
            Dim entry As New ZipEntry(Dir.FullName.Replace(parentPath, "") + "/" + fi.Name)
            entry.Size = fs.Length
            fs.Close()
            s.PutNextEntry(entry)
            s.Write(Buffer, 0, Buffer.Length)
        Next
    End Sub
Ich habe diesen code nun mal versucht zu verwenden doch leider stoße ich auf ein problem, mir wird folgende meldung wiedergeben beim zippen.

Code:
size was 167405, but I expected 167404
Die Zip wurde zwar erstellt, mir wird aber beim öffnen der Zip als fehlermeldung ausgegeben, das das Archiv ein unerwartetes archivende besitzt!

Hat jemand eine Lösung?

Peter86
 
Zuletzt bearbeitet: