Laden...

SharpZipLib mach sporadisch Zipdatei kaputt..

Erstellt von Cornflake vor 8 Jahren Letzter Beitrag vor 8 Jahren 2.124 Views
C
Cornflake Themenstarter:in
142 Beiträge seit 2007
vor 8 Jahren
SharpZipLib mach sporadisch Zipdatei kaputt..

Hallo Leute

Habe mal geschaut ob es zu meinem Problem hier im Forum eine Lösung gibt. Leider gibts nur einen passenden Thread, der aber nie richtig beantwortet wurde.
SharpZipLib prooduziert sporadisch defekte Archive

Hab mich letzten riesig gefreut, dass SharpZipLib funzt. Nur auf einmal gabs Fehler, die ich erst durch Löschen meiner Zip Datei wieder beheben konnte. Daher hab ich mir ein kleines Testprogramm geschrieben, mit zwei Textboxen und Buttons. in der ersten Textbox wird der Text als Textdatei im Zip gespeichert und in der Zweiten wieder aus der Zip Datei die Textdatei in die Textbox gelesen.

Ich habe herausgefunden, wenn ich mehr als 4096 Byte ( bzw. größer als Buffer) in die Zipdatei meine Textdatei wiederholt reinschreibe und danach den Inhalt der Textdatei verkleinere, erneut speicher und teilweise das Programm neu starte, es sporadisch zu einem Fehler in der Zipdatei kommt.

Die Zipdatei lässt sich dann noch in 7Zip öffnen und die Textdatei ohne Fehler im Texteditor öffnen, aber der Windows Explorer kann mit der Zipdatei nichts mehr anfangen und bei "7zip Archiv überprüfen", wird festgestellt, dass:> Fehlermeldung:

Warnings: There are some data after the end of the payload data

Update:
Ziemlich sicher kann ich den Fehler repoduzieren wenn ich z.B. 8000 Byte einfüge speichere, dann auslesen, dann 5000 Byte wegnehme, speichere. Das Auslesen bringt dann einen > Fehlermeldung:

Wrong Central Directory signature. Fehler.

Ich vermute daher irgendwas stimmt beim Aufräumen nicht. Anbei der ungeänderte Testcode in C#


namespace ZipFile_test
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        string Filepath = "test.zip";
         
        /// <summary>
        /// Packen
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {  
            FileStream fso = File.OpenWrite(Filepath);

            using (ZipOutputStream zos = new ZipOutputStream(fso))
            {
                zos.SetLevel(8); 

                ZipEntry ze = new ZipEntry(("Testordner\\test.txt").Replace("\\", "/"));
                ze.DateTime = DateTime.Now; 
                ze.Size = GetStreamFromString(textBox1.Text).Length;

                zos.PutNextEntry(ze);

                using (Stream si = GetStreamFromString(textBox1.Text))
                { StreamUtils.Copy(si, zos, new byte[4096]); }

                bool t = zos.IsFinished; 
                  
                zos.Finish();
                zos.Flush();
                zos.Close();
            }

            fso.Close(); 

            button1.Text = "ZIP = " + textBox1.Text.Length;
        }


        public Stream GetStreamFromString(string s)
        {
            MemoryStream stream = new MemoryStream();
            StreamWriter writer = new StreamWriter(stream);
            writer.Write(s);
            writer.Flush();
            stream.Position = 0;
            return stream;
        }

        /// <summary>
        /// Entpacken
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {

            if (!System.IO.File.Exists(Filepath))   return ;

            FileStream fsi = File.OpenRead(Filepath);

            ZipFile zipFile = new ZipFile(fsi);

            ZipEntry ze = zipFile.GetEntry("Testordner\\test.txt".Replace("\\", "/"));

            Stream zs = zipFile.GetInputStream(ze);
            StreamReader sr = new StreamReader(zs);

            string konfig = sr.ReadToEnd();

            sr.Close();
            zs.Close();  
            fsi.Close();
              
            textBox2.Text = konfig;
             
            button2.Text = "UnZIP = " + textBox2.Text.Length;
        } 
    }
}

Vllt könnt ihr den Fehler ja nachvollziehen.
Benötigt wird eine leere Windows Forms Anwendung in der 2x Textbox und 2x Button enthalten ist und die SharpZipLib enthalten sein muss.

Vielen Dank
Cornflake

656 Beiträge seit 2008
vor 8 Jahren

Wenn die Datei beim Aufruf von File.OpenWrite schon existiert, wird sie nicht geleert. Das heißt, am Ende bleibt möglicherweise Müll aus der alten Zip zurück, wenn die neue kleiner ist (denn bei einer Zip steht die Struktur, Dateinamen usw. am Ende der Datei).
Versuchs mal mit File.Open(Filepath, FileMode.Create) - damit wird die Datei entweder neu angelegt (wenn sie noch nicht existiert) oder auf 0 bytes truncated (wenn sie existiert). File.OpenWrite benutzt intern nämlich nur FileMode.OpenOrCreate, womit die Größe der Datei initial erhalten bleibt.

C
Cornflake Themenstarter:in
142 Beiträge seit 2007
vor 8 Jahren

Hallo
Danke für deine Antwort. Vllt. nutze ich die Zip Datei ja auch falsch.
Allerdings wenn ich das mit einem Zip Programm mache (7zip) gibts keine Probleme.

Ich habe vor in der Zipdatei diese Testdatei, bei Änderungen zu überschreiben.
Der Gedanke dahinter. in der endgültigen Zipdatei liegen mehrere Dateien und Ordner und bestimmte Dateien möchte ich auslesen und auch wieder geändert zurückschreiben ohne jedesmal alles zu löschen.

Grüße Cornflake

16.842 Beiträge seit 2008
vor 8 Jahren

Also was definitiv mal falsch ist, ist Dein Umgang mit Streams.
Du verwendest zwar bereits using() - aber sieht nicht so aus, als ob Du weisst, was Du da tust 😉

C
Cornflake Themenstarter:in
142 Beiträge seit 2007
vor 8 Jahren

@Abt
Kann sein, dass ich die nicht ganz sauber verwende.

Die zos Variable wird beim Verlassen der using Klammern automatisch geschlossen und disposed. Dennoch habe ich ein Close() dazugeschrieben, damit der Stream definitiv vorher geschlossen wird, was man evtl weglassen kann. Aber wichtig die Streams sind bis zum Ende der Benutzung offen.

Über die GetStreamFromString() Methode hole ich mir einmal die Länge und zum anderen wird der Stream zum Schreiben der Datei in die Zipdatei verwendet. Ist an dieser Methode etwas falsch? Ich wüsste sonst nicht wie ich aus einem String einen Stream machen kann.

Was würdest du da anders machen, bzw. was mache ich falsch?

Inzwischen habe ich mir überlegt, vor jedem erneuten Schreiben der Datei eine evtl. in der Zipdatei vorhandene Datei vorher zu löschen. Leider will mich SharpZipLib kein Delete durchführen lassen und wirft an anderer Stelle eine Fehlermeldung.

Hier mein zusätzlicher Code vor dem Schreiben der Datei in die Zipdatei.


...
 private void button1_Click(object sender, EventArgs e)
        {  
            //Evtl. vorhandenen Eintrag vorher löschen
            if (File.Exists(Filepath))
            {
                ZipFile fz = new ZipFile(Filepath);
                ZipEntry zen = fz.GetEntry("Testordner\\test.txt".Replace("\\", "/"));                
                if (zen != null) fz.Delete(zen);   //Hier kommt der Fehler InvalidOperationException("BeginUpdate has not been called")
                fz.Close();
            }

            FileStream fso = File.OpenWrite(Filepath);
...

16.842 Beiträge seit 2008
vor 8 Jahren

Was genau soll Dein Replace an der Stelle und wieso nimmst Du nicht ZipEntry.CleanName?

Für ein Update oder Change (ein Delete is ein Change) muss zipFile.BeginUpdate(); ausgeführt werden.
Das steht auch in der Doku bzw. solltest Du das mit Sicherheit mit der Fehlermeldung finden.

Hat aber nix mit einer kaputten Zip zutun...

C
Cornflake Themenstarter:in
142 Beiträge seit 2007
vor 8 Jahren

@Abt Dank für deine Infos. 👍
CleanName hatte ich noch nicht gelesen und das BeginUpdate() wohl auch nicht 🤔. Hatte als Doku bisher mehr die Samples verwendet.

Durch das immer vorherige Löschen einer schon vorhandenen gezippten Datei, habe ich jetzt auch keine Fehlermeldung mehr 🙂