Pergunta

Eu tenho um datatable que eu quero convertê -lo para XML e depois zombar, usando o DotNetzip. Finalmente, o usuário pode baixá -lo via página da web ASP.NET. Meu código abaixo

    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();

O arquivo XML no arquivo zip está vazio.

Foi útil?

Solução

2 coisas. Primeiro, se você mantiver o design do código que você possui, precisará executar um Seek () no MemoryStream antes de escrevê -lo na entrada.

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); 
}

Mesmo se você mantiver esse design, eu sugeriria uma cláusula de uso (), como mostrei, e como descrito em todos os Exemplos de Dotnetzip, em vez de chamar DISPOSE (). A cláusula de uso () é mais confiável diante das falhas.

Agora você pode se perguntar: por que é necessário procurar no MemoryStream antes de ligar para Addentry ()? O motivo é que addentry () foi projetado para apoiar os chamadores que passam por um fluxo onde a posição é importante. Nesse caso, o chamador precisa que os dados de entrada sejam lidos no fluxo, usando a posição atual do fluxo. Addentry () suporta isso. Portanto, defina a posição no fluxo antes de chamar addEntry ().

Mas, melhor a opção é modificar seu código para usar o Sobrecarga de addEntry () que aceita umlegate. Foi projetado especificamente para adicionar conjuntos de dados em arquivos ZIP. Seu código original grava o conjunto de dados em um fluxo de memória e, em seguida, procura no fluxo e grava o conteúdo do fluxo no zip. É mais rápido e mais fácil se você escrever os dados uma vez, que é o que o WritedElegate permite que você faça. O código se parece com o seguinte:

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); 
}

Isso grava o conjunto de dados diretamente no fluxo compactado no ZipFile. Muito eficiente! Sem buffer duplo. O delegado anônimo é chamado no momento do zipfile.save (). Apenas uma gravação (+compressa) é realizada.

Outras dicas

Por que você não fechou o MemoryStream, eu envolveria isso em um using Cláusula, o mesmo poderia ser dito para zipFile? Também dt Presumo que seja um datatable ... coloque a verificação de erros para ver se há linhas, veja o código abaixo ...

    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...

Editar: Tendo olhado para isso de novo, e percebendo que Ionic.ziplib Do codePlex foi usado, mudei um pouco o código, em vez de zipFile.Save(Response.OutputStream); eu usei zipFile.Save(stream); usando o stream instância do MemoryStream aula e escreva usando Response.Write(stream);.

Editar#2: Graças a Cheeso + Mikael Por apontar a falha óbvia - eu perdi uma milha de distância e não entendi o comentário deles até perceber que o fluxo estava no final ...

Você já tentou lavar o fluxo antes de fechar?

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

OK. Não parece que estamos chegando muito longe aqui, então você precisa começar a depurar um pouco mais.

Atualize seu código para fazer o seguinte:

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

Veja se você possui um arquivo XML válido. Se você seguir em frente, faça o mesmo com o seu ZipFile. Salve -o em um arquivo local. Veja se está lá, possui seu arquivo XML e seu arquivo XML possui conteúdo.

Se isso funcionar, tente enviar de volta apenas o fluxo de memória como resposta, veja se isso funciona.

Você deve poder rastrear ainda mais o problema.

Adicione um cabeçalho de contentType:

Response.ContentType = "application/zip";

Isso permitirá que os navegadores detectem o que você está enviando.

Verifique duas vezes o fluxo que você está retornando também. No seu exemplo abaixo

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

Você está salvando o ZipFile no seu fluxo de resposta usando o método SALVE, mas também está chamando a resposta.Write () com uma variável ZipStream. O que é ZipStream? Verifique se também não é um fluxo vazio.

Criando um arquivo zip a partir do fluxo e baixando -o. Abaixo está o código.

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());

Este código o ajudará a baixar um arquivo do Stream.

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 necessários:

using System.IO.Compression;
using System.IO.Compression.ZipArchive;
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top