我正在使用ICSharpCode.SharpZipLib v 0.86.0.518。
我有一个流,其内容我想作为文件添加到Zip,它也必须在内存中创建(而不是在磁盘上)。
生成的Zip会打开以供浏览,但在尝试提取任何内容时,我收到一条错误消息,指出“存档处于未知格式或已损坏”。
在下面的代码中,asZip=false
发送文本文件,并按预期收到。当asZip=true
时,文件被发送,但遭受上述损坏。
当我用MemoryStream zipStream
替换FileStream zipStream
时,磁盘上的文件就可以了。
谁能看到我错过的东西?
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net; // .NET 4.0
using System.Net.Http;
using System.Net.Http.Headers;
using System.Web.Mvc;
using ICSharpCode.SharpZipLib.Zip;//0.86.0.518
namespace Demo
{
public class DemoApiController : Controller
{
/// <summary>
/// demos the zipfile error
/// </summary>
/// <param name="withFiles">Creates the zip if set to <c>true</c> [with files].</param>
[HttpGet]
public void ZipErrorDemo(bool asZip)
{
const string fileContent = "Hello World!";
MemoryStream rawContentStream = new MemoryStream(System.Text.Encoding.ASCII.GetBytes(fileContent));
if (!asZip)
{
//This File is recieved as text, opens without erros and has correct content.
WriteStreamToDownload(rawContentStream, "text/plain", "HelloWorld.txt");
}
else
{
MemoryStream zipStream = new MemoryStream(1024 * 2048);//2MB
using (ZipOutputStream s = new ZipOutputStream(zipStream))
{
s.UseZip64 = ICSharpCode.SharpZipLib.Zip.UseZip64.Off; //No Zip64 for better compatability
s.SetLevel(0); //No compression
byte[] buffer = new byte[4096];
//Add the text file
ZipEntry csvEntry = new ZipEntry("HelloWorld.txt");
s.PutNextEntry(csvEntry);
int sourceBytes = 0;
do
{
sourceBytes = rawContentStream.Read(buffer, 0, buffer.Length);
s.Write(buffer, 0, sourceBytes);
} while (sourceBytes > 0);
s.CloseEntry();
s.IsStreamOwner = false;//Tells s.Close to not mess invoke zipStream.Close()
s.Flush();
s.Finish();
s.Close();
byte[] streamBuffer = zipStream.GetBuffer();//Before doing this things were worse.
MemoryStream newStream = new MemoryStream(streamBuffer);
//This File is recieved as a zip, opens to list contents, but atemtps at extraction result in an error.
WriteStreamToDownload(newStream, "application/zip", "HelloWorld.zip");
}
}
}
// Adapted from: http://stackoverflow.com/questions/5596747/download-stream-file-from-url-asp-net
// Accessed: 3/17/15. Works.
private static void WriteStreamToDownload(Stream stream, string contentType, string fileName)
{
// 100 kb
const int bytesToRead = 102400;
byte[] buffer = new byte[bytesToRead];
var contextResponse = System.Web.HttpContext.Current.Response;
try
{
contextResponse.ContentType = contentType;
contextResponse.AddHeader("Content-Disposition", "attachment; filename=\"" + Path.GetFileName(fileName) + "\"");
contextResponse.AddHeader("Content-Length", stream.Length.ToString());
int length;
do
{
if (contextResponse.IsClientConnected)
{
length = stream.Read(buffer, 0, bytesToRead);
contextResponse.OutputStream.Write(buffer, 0, length);
contextResponse.Flush();
buffer = new byte[bytesToRead];
}
else
{
length = -1;
}
} while (length > 0);
}
finally
{
if (stream != null)
{
stream.Close();
stream.Dispose();
}
}
}
}
}
答案 0 :(得分:3)
目前,您正在阅读您的信息流。 GetBuffer()
返回超大支持缓冲区;你通常应该将自己限制在缓冲区的第一个zipStream.Length
字节。
所以首先要尝试的是:
MemoryStream newStream = new MemoryStream(streamBuffer, 0
(int)zipStream.Length);
但是,如果可以,只要您发送zipStream
,您也可以实现相同的目标:
using
您可能也有兴趣听说.NET框架内部存在zip支持,而无需其他工具。
您的复制代码(btw)效率低下(特别是在不断重新创建缓冲区时)并且可能只是使用:
stream.CopyTo(contextResponse.OutputStream);