Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/335.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用SharpZipLib在内存中创建Zip导致存档损坏_C#_.net_Memorystream_Sharpziplib - Fatal编程技术网

C# 使用SharpZipLib在内存中创建Zip导致存档损坏

C# 使用SharpZipLib在内存中创建Zip导致存档损坏,c#,.net,memorystream,sharpziplib,C#,.net,Memorystream,Sharpziplib,我正在使用ICSharpCode.SharpZipLib v 0.86.0.518 我有一个流,我想将其内容作为文件添加到Zip中,它也必须在内存中创建(而不是在磁盘上) 生成的Zip将打开以供浏览,但在尝试提取任何内容时,我会收到一个错误,指出“存档文件的格式未知或已损坏” 在下面的代码中,当asZip=false文本文件按预期发送和接收。当asZip=true时,文件将被发送,但会遭受上述损坏 当我用FileStream zipStream替换MemoryStream zipStream时,

我正在使用ICSharpCode.SharpZipLib v 0.86.0.518

我有一个流,我想将其内容作为文件添加到Zip中,它也必须在内存中创建(而不是在磁盘上)

生成的Zip将打开以供浏览,但在尝试提取任何内容时,我会收到一个错误,指出“存档文件的格式未知或已损坏”

在下面的代码中,当
asZip=false
文本文件按预期发送和接收。当
asZip=true
时,文件将被发送,但会遭受上述损坏

当我用
FileStream zipStream
替换
MemoryStream 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();
                }
            }
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.IO;
使用System.Linq;
使用System.Net;//。NET 4.0
使用System.Net.Http;
使用System.Net.Http.Header;
使用System.Web.Mvc;
使用ICSharpCode.SharpZipLib.Zip//0.86.0.518
名称空间演示
{
公共类控制器:控制器
{
/// 
///演示zipfile错误
/// 
///如果设置为true[带文件],则创建zip。
[HttpGet]
公共空间Ziperordemo(bool asZip)
{
const string fileContent=“Hello World!”;
MemoryStream rawContentStream=新的MemoryStream(System.Text.Encoding.ASCII.GetBytes(fileContent));
如果(!asZip)
{
//此文件以文本形式接收,打开时无错误,内容正确。
WriteStreamToDownload(rawContentStream、“text/plain”、“HelloWorld.txt”);
}
其他的
{
MemoryStream zipStream=新的MemoryStream(1024*2048);//2MB
使用(ZipOutStream s=新ZipOutStream(zipStream))
{
s、 UseZip64=ICSharpCode.SharpZipLib.Zip.UseZip64.Off;//无Zip64以获得更好的兼容性
s、 SetLevel(0);//无压缩
字节[]缓冲区=新字节[4096];
//添加文本文件
ZipEntry csvEntry=新ZipEntry(“HelloWorld.txt”);
s、 PutNextEntry(csvEntry);
int sourceBytes=0;
做
{
sourceBytes=rawContentStream.Read(buffer,0,buffer.Length);
s、 写入(缓冲区,0,源字节);
}而(sourceBytes>0);
s、 CloseEntry();
s、 IsStreamOwner=false;//告诉s.Close不要乱调用zipStream.Close()
s、 冲洗();
s、 完成();
s、 Close();
byte[]streamBuffer=zipStream.GetBuffer();//在执行此操作之前,情况更糟。
MemoryStream newStream=新的MemoryStream(streamBuffer);
//此文件作为zip接收,打开以列出内容,但提取时atemtps会导致错误。
WriteStreamToDownload(newStream,“application/zip”,“HelloWorld.zip”);
}
}
}
//改编自:http://stackoverflow.com/questions/5596747/download-stream-file-from-url-asp-net
//访问日期:2015年3月17日。工程。
私有静态void WriteStreamToDownload(流、字符串内容类型、字符串文件名)
{
//100KB
常量int bytesToRead=102400;
byte[]buffer=新字节[bytesToRead];
var contextResponse=System.Web.HttpContext.Current.Response;
尝试
{
contextResponse.ContentType=ContentType;
contextResponse.AddHeader(“内容处置”、“附件;文件名=\”“+Path.GetFileName(文件名)+\”);
AddHeader(“内容长度”,stream.Length.ToString());
整数长度;
做
{
if(contextResponse.IsClientConnected)
{
长度=stream.Read(缓冲区,0,bytesToRead);
contextResponse.OutputStream.Write(缓冲区,0,长度);
contextResponse.Flush();
buffer=新字节[bytesToRead];
}
其他的
{
长度=-1;
}
}而(长度>0);
}
最后
{
if(流!=null)
{
stream.Close();
stream.Dispose();
}
}
}
}
}

目前,您正在过度阅读您的流
GetBuffer()
返回过大的后备缓冲区;您通常应该将自己限制在缓冲区的第一个
zipStream.Length
字节

因此,首先要尝试的是:

MemoryStream newStream = new MemoryStream(streamBuffer, 0
    (int)zipStream.Length);
但是,如果这样做有效,您也可以通过发送
zipStream
来实现同样的效果,只要您:

  • 写后倒流
  • 使用
您可能还感兴趣的是,zip支持存在于.NET框架本身中,而不需要额外的工具

顺便说一句,您的复制代码效率很低(特别是在不断重新创建缓冲区时),可能仅使用:

stream.CopyTo(contextResponse.OutputStream);

目前,您正在过度阅读您的流
GetBuffer()
返回过大的后备缓冲区;您通常应该将自己限制在缓冲区的第一个
zipStream.Length
字节

因此,首先要尝试的是:

MemoryStream newStream = new MemoryStream(streamBuffer, 0
    (int)zipStream.Length);
但是,如果这样做有效,您也可以通过发送
zipStream
来实现同样的效果,只要您:

  • 倒带strea