2011-07-12 33 views
5

Estoy tratando de crear archivos zip dinámicamente en el servidor que incluye fotos de servicios en línea. Pero cuando intento abrir el archivo, WinRar dice que el archivo es un formato desconocido o está dañado.Creando zip en C# con System.IO.Packaging

este es el código:

MemoryStream stream = new MemoryStream(); 
Package package = ZipPackage.Open(stream, FileMode.Create, FileAccess.ReadWrite); 

foreach (Order o in orders) 
{ 
    o.GetImages(); 

    Parallel.ForEach(o.Images, (Dictionary<string, object> image) => 
    { 
     string imageId = (string)image["ID"]; 
     int orderId = (int)image["OrderId"]; 
     string fileName = (string)image["FileName"]; 
     string url = (string)image["URL"]; 

     if (string.IsNullOrEmpty(fileName)) 
     { 
      System.Net.WebClient wc = new System.Net.WebClient(); 
      byte[] data = wc.DownloadData(url); 
      MemoryStream ms = new MemoryStream(data); 
      ms.Write(data, 0, data.Length); 

      string ext; 

      switch(wc.ResponseHeaders["Content-Type"]) 
      { 
       case "image/jpeg": 
       case "image/jpg": 
       ext = "jpg"; 
        break; 

       case "image/png": 
        ext = "png"; 
        break; 

       case "image/gif": 
        ext = "gif"; 
        break; 

       default : 
        ext = "un"; 
        break; 
      } 

      Uri uri = new Uri("/" + orderId.ToString() + "/" + imageId + "." + ext, UriKind.Relative); 

      var part = package.CreatePart(uri, wc.ResponseHeaders["Content-Type"], CompressionOption.NotCompressed); 

      var pstream = part.GetStream(FileMode.Open, FileAccess.ReadWrite); 

      pstream.Write(data, 0, data.Length); 

      var rel = package.CreateRelationship(part.Uri, TargetMode.Internal, "http://example.com/AlbumImage"); 


     } 
    }); 
} 

package.Flush(); 

byte[] fileBytes = new byte[stream.Length]; 
stream.Read(fileBytes, 0, Convert.ToInt32(stream.Length)); 

Response.Clear(); 
Response.AddHeader("Content-Disposition", "attachment; filename=Orders.zip"); 
Response.AddHeader("Content-Length", stream.Length.ToString()); 
Response.ContentType = "application/octet-stream"; 
Response.BinaryWrite(fileBytes); 
Response.End(); 
+3

Has probado esto con una sola orden con una imagen? ¿Has intentado utilizar un 'foreach' común en lugar de' Parallel.ForEach'? ¿El subproceso 'Package' está seguro en la llamada a' CreatePart'? Parece que vas a escribir en la transmisión desde múltiples hilos, y a menos que 'CreatePart' sea seguro para los hilos, entonces obtendrás una transmisión dañada. –

+0

Lo he estado haciendo ahora en una sola imagen, por lo que la seguridad del hilo no debería ser un problema aquí – aikixd

+0

Probado con foreach común. no hay cambios – aikixd

Respuesta

1

Se trata de Paquete Uris. También hemos sido golpeados por ellos. Aquí está la muestra de trabajo para almacenar dos archivos en zip. Código recién copiado de nuestro proyecto con la eliminación de algunos datos privados.

  var dataFilePath = Path.GetFileName(dataFileName); 
      var dataFileUri = PackUriHelper.CreatePartUri(new Uri(dataFilePath, UriKind.Relative)); 
      // Create the Package 
      using (var package = Package.Open(filePath, FileMode.Create)) 
      { 
       // Add the diagram view part to the Package 
       var pkgPart = package.CreatePart(dataFileUri, MediaTypeNames.Application.Octet); 
       var pkgStream = pkgPart.GetStream(); 

       // Copy the data to the model view part 
       // diagramFileName Encoding.Default.GetBytes(text) 
       using (var modelStream = new FileStream(dataFileName, FileMode.Open, FileAccess.Read)) 
       { 
        const int bufSize = 0x1000; 
        var buf = new byte[bufSize]; 
        int bytesRead; 
        while ((bytesRead = modelStream.Read(buf, 0, bufSize)) > 0) 
        { 
         pkgStream.Write(buf, 0, bytesRead); 
        } 
       } 

       // Add a context Part to the Package 
       var pkgPartContext = package.CreatePart(ctxUri, MediaTypeNames.Application.Octet); 
       var ctxPkgStream = pkgPartContext.GetStream(); 

       // Copy the data to the context part 
       using (var ctxStream = new FileStream(ctxFileName, FileMode.Open, FileAccess.Read)) 
       { 
        const int bufSize = 0x1000; 
        var buf = new byte[bufSize]; 
        int bytesRead; 
        while ((bytesRead = ctxStream.Read(buf, 0, bufSize)) > 0) 
        { 
         ctxPkgStream.Write(buf, 0, bytesRead); 
        } 
       } 
      } 

      // remove tmp files 
      File.Delete(ctxFileName); 
      File.Delete(dataFileName); 
+1

Utiliza filePath al invocar el paquete. Puede ver por mis comentarios a la pregunta, que esto funcionó para mí también. El problema se produce cuando uso la transmisión como almacenamiento para los datos. Parece que en el escenario de flujo se debe tener un cuidado adicional. O este es un error. – aikixd

+0

¿Cuál es el propósito de esto: MemoryStream ms = new MemoryStream (datos); ms.Write (data, 0, data.Length); Nunca usas ms y nunca deshaces? –

+0

¿Se puede rebobinar la posición de la secuencia a 0 ?. before stream.Read (fileBytes, 0, Convert.ToInt32 (stream.Length)); –

0

Sé que esta pregunta es un poco antigua pero tuve un problema similar. Solía ​​

stream.Seek(0, SeekOrigin.Begin); 

y funcionó

Cuestiones relacionadas