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
 
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
 
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.
 
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
 
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
 
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.
 
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
 
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
 
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
 
Zurück