Frage

Ich habe eine Datatable, dass ich es in XML konvertieren möchten, und zip es dann, mit DotNetZip. schließlich kann der Benutzer es über Asp.Net Webseite herunterladen. Mein Code in unten

    dt.TableName = "Declaration";

    MemoryStream stream = new MemoryStream();
    dt.WriteXml(stream);

    ZipFile zipFile = new ZipFile();
    zipFile.AddEntry("Report.xml", "", stream);
    Response.ClearContent();
    Response.ClearHeaders();
    Response.AppendHeader("content-disposition", "attachment; filename=Report.zip");

    zipFile.Save(Response.OutputStream);
    //Response.Write(zipstream);
    zipFile.Dispose();

die XML-Datei in Zip-Datei ist leer.

War es hilfreich?

Lösung

2 Dinge. Erstens, wenn Sie den Code Design halten Sie haben, müssen Sie ein () auf der Memory Suche durchführen, bevor es in den Eintrag zu schreiben.

dt.TableName = "Declaration"; 

MemoryStream stream = new MemoryStream(); 
dt.WriteXml(stream); 
stream.Seek(0,SeekOrigin.Begin);   // <-- must do this after writing the stream!

using (ZipFile zipFile = new ZipFile())
{
  zipFile.AddEntry("Report.xml", "", stream); 
  Response.ClearContent(); 
  Response.ClearHeaders(); 
  Response.AppendHeader("content-disposition", "attachment; filename=Report.zip"); 

  zipFile.Save(Response.OutputStream); 
}

Auch wenn Sie diesen Entwurf zu halten, würde ich eine () verwendet Klausel vorschlagen, wie ich gezeigt habe, und wie in allen DotNetZip Beispiele , statt Entsorgen () aufrufen. Die Verwendung von () Klausel ist zuverlässiger angesichts der Ausfälle.

  

Jetzt fragen Sie sich vielleicht, warum ist es notwendig, in der Memorystream zu suchen, bevor AddEntry () aufrufen? Der Grund dafür ist, AddEntry () wird entworfen, um jene Anrufer zu unterstützen, die einen Strom passieren, wo die Position wichtig ist. In diesem Fall muss der Anrufer der Eingabedaten aus dem Stream zu lesen, die aktuelle Position des Stroms mit . AddEntry () unterstützt das. Daher stellen Sie die Position im Stream vor dem Aufruf AddEntry ().

Aber die bessere Option ist, den Code zu modifizieren, um die Überlastung der AddEntry (), die eine WriteDelegate annimmt. Es wurde für das Hinzufügen von Datensätzen in Zip-Dateien entwickelt. Ihr Original-Code schreibt den Datensatz in einen Speicherstream, sucht dann auf dem Strom, und schreibt den Inhalt des Stroms in den Reißverschluss. Es ist schneller und einfacher, wenn Sie die Daten einmal schreiben, das ist, was die WriteDelegate Sie tun können. Der Code sieht wie folgt aus:

dt.TableName = "Declaration"; 
Response.ClearContent(); 
Response.ClearHeaders(); 
Response.ContentType = "application/zip";
Response.AppendHeader("content-disposition", "attachment; filename=Report.zip"); 

using(Ionic.Zip.ZipFile zipFile = new Ionic.Zip.ZipFile())
{
    zipFile.AddEntry("Report.xml", (name,stream) => dt.WriteXml(stream) );
    zipFile.Save(Response.OutputStream); 
}

Dies schreibt den Datensatz direkt in den komprimierten Strom in der Zip-Datei. Sehr effizient! Kein Double-Buffering. Der anonyme Delegat wird zum Zeitpunkt der ZipFile.Save () aufgerufen. Nur ein Schreib (+ Kompresse) durchgeführt wird.

Andere Tipps

Warum hast du nicht in der Nähe der Memorystream, ich würde wickeln, dass in einer using Klausel könnte das gleiche für zipFile gesagt werden? Auch dt nehme ich an ein Datatable ... in Fehlerüberprüfung, um zu sehen, ob es Zeilen ist, sehen Sie den Code unten ...

    dt.TableName = "Declaration"; 

    if (dt.Rows != null && dt.Rows.Count >= 1){
      using (MemoryStream stream = new MemoryStream()){
         dt.WriteXml(stream); 

         // Thanks Cheeso/Mikael
         stream.Seek(0, SeekOrigin.Begin);
         //

         using (ZipFile zipFile = new ZipFile()){
             zipFile.AddEntry("Report.xml", "", stream); 
             Response.ClearContent(); 
             Response.ClearHeaders(); 
             Response.AppendHeader("content-disposition", "attachment; filename=Report.zip"); 

             //zipFile.Save(Response.OutputStream); 
             zipFile.Save(stream);

             // Commented this out
             /*
               Response.Write(zipstream); // <----- Where did that come from?
             */
          }
          Response.Write(stream);
       } 
    }
    // No rows...don't bother...

Edit: bei dieser Nachdem wieder sah, und zu erkennen, dass Ionic.Ziplib von Codeplex verwendet wurde, änderte ich den Code leicht, statt zipFile.Save(Response.OutputStream); habe ich zipFile.Save(stream); die stream Instanz der MemoryStream-Klasse und schreiben sie es mit Response.Write(stream); aus.

Bearbeiten # 2: Mit Cheeso + Mikael für den Hinweis auf die offensichtlichen Fehler - ich vermisste ihm eine Meile entfernt und haben nicht verstanden, ihren Kommentar, bis ich erkennen, dass der Strom am Ende war ...

Haben Sie versucht, den Strom zu spülen, bevor zippen?

dt.WriteXml(stream);
stream.Flush();
ZipFile zipFile = new ZipFile();

Ok. Es scheint nicht, wie wir bekommen sehr weit hier, so dass Sie beginnen müssen diese ein bisschen mehr debuggen.

Aktualisieren Sie sind Code folgendes zu tun:

dt.WriteXml(stream);
stream.Seek(0, SeekOrigin.Begin);
File.WriteAllBytes("c:\test.xml", stream.GetBuffer());

Sehen Sie, wenn Sie eine gültige XML-Datei aus haben. Wenn Sie dann auf verschiebe das gleiche mit Ihrem ZipFile. Speichern Sie es in einer lokalen Datei. Sehen Sie, wenn es da ist, hat Ihre XML-Datei und die XML-Datei hat Inhalt in ihm.

Wenn das funktioniert, versuche, wieder nur den Speicherstrom als Antwort sendet, sehen, ob das funktioniert.

Sie sollten dann in der Lage sein, das Problem zu verfolgen weiter unten.

ein Contenttype-Header hinzufügen:

Response.ContentType = "application/zip";

das wird dem Browser erlauben zu erkennen, was Sie senden.

Überprüfen Sie den Stream Sie zurück zu kehren. In Ihrem Beispiel unter

zipFile.Save(Response.OutputStream);
Response.Write(zipstream);
zipFile.Dispose();

Sie sparen die Zip-Datei auf Ihre Antwort Strom die Save-Methode verwenden, aber dann rufen Sie auch Response.Write () mit einem zipstream variabel. Was ist zipstream? Überprüfen Sie, ob es nicht auch ein leerer Strom ist.

eine Zip-Datei aus dem Strom erzeugen und es herunterladen. Unten ist der Code.

FileStream stream=File.OpenRead(@"D:\FileDownLoad\DeskTop\1.txt");
MemoryStream MS=new MemoryStream();

ZipOutputStream zipOutputStream = new ZipOutputStream(MS);
zipOutputStream.SetLevel(9);
ZipEntry entry = new ZipEntry("1.txt");
zipOutputStream.PutNextEntry(entry);

byte[] buffer = new byte[stream.Length];
int byteRead = 0;

while ((byteRead = stream.Read(buffer, 0, buffer.Length)) > 0) 
    zipOutputStream.Write(buffer, 0, byteRead);

    zipOutputStream.IsStreamOwner = false;
    stream.Close();
    zipOutputStream.Close();
    MS.Position = 0;

    Response.ContentType = "application/application/octet-stream";
    Response.AppendHeader("content-disposition", "attachment; filename=\"Download.zip\"");
    Response.BinaryWrite(MS.ToArray());

Dieser Code wird Ihnen helfen, eine Datei aus dem Strom in herunterzuladen.

using (var outStream = new MemoryStream())
{
    using (var archive = new ZipArchive(outStream, ZipArchiveMode.Create, true))
    {
        var fileInArchive = archive.CreateEntry("FileName.pdf", CompressionLevel.Optimal);
        using (var entryStream = fileInArchive.Open())
        using (WebResponse response = req.GetResponse())
        {
            using (var fileToCompressStream = response.GetResponseStream())
            {
                fileToCompressStream.CopyTo(entryStream);
            }
        }                       
    }
    using (var fileStream = new FileStream(@"D:\test.zip", FileMode.Create))
    {
        outStream.Seek(0, SeekOrigin.Begin);
        outStream.CopyTo(fileStream);
    }
}

Namespaces erforderlich:

using System.IO.Compression;
using System.IO.Compression.ZipArchive;
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top