使用写入ZipArchive HttpContext的的OutputStream [英] Writing to ZipArchive using the HttpContext OutputStream

查看:407
本文介绍了使用写入ZipArchive HttpContext的的OutputStream的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直试图让新ZipArchive包含在.NET 4.5( System.IO.Com pression.ZipArchive ),以在工作ASP.NET网站。但现在看来似乎不喜欢写的流 HttpContext.Response.OutputStream

我的关注code例子会抛出


  

System.NotSupportedException:不支持指定的方法。


只要在写入的数据流。

在流上的 CanWrite 属性返回true。

如果我用FILESTREAM交换的OutputStream,指向一个本地目录,它的工作原理。是什么给了?

  ZipArchive存档=新的ZipArchive(HttpContext.Response.OutputStream,ZipArchiveMode.Create,FALSE);ZipArchiveEntry条目= archive.CreateEntry(文件名);使用(StreamWriter的作家=新的StreamWriter(entry.Open()))
{
    writer.WriteLine(关于这个包的信息。);
    writer.WriteLine(========================);
}

堆栈跟踪:

[NotSupportedException异常:不支持指定方法]
System.Web.Htt presponseStream.get_Position()+29
System.IO.Com pression.ZipArchiveEntry.WriteLocalFileHeader(布尔isEmptyFile)+389
System.IO.Com pression.DirectToArchiveWriterStream.Write(字节[]缓冲区,偏移的Int32,的Int32计数)+94
System.IO.Com pression.WrappedStream.Write(字节[]缓冲区,偏移的Int32,的Int32计数)+41


解决方案

Calbertoferreira的回答有一些有用的信息,但得出的结论是错误的大部分。要创建一个档案,你不需要寻找,但你必须要能够读位置

根据文档,读位置应仅用于查找流的支持,但 ZipArchive 似乎需要这甚至来自非查找流,我认为这是<一个href=\"https://connect.microsoft.com/VisualStudio/feedback/details/816411/ziparchive-shouldnt-read-the-position-of-non-seekable-streams\">a错误。

因此​​,所有你需要做的,支持直接写入ZIP文件的OutputStream 是包装在一个自定义的支持让位置。是这样的:

 类PositionWrapperStream:流
{
    私人只读流包裹;    私人INT POS = 0;    公共PositionWrapperStream(流包裹)
    {
        this.wrapped =包裹;
    }    公众覆盖布尔CanSeek {{返回FALSE; }}    公众覆盖布尔CanWrite {获得{返回true; }}    公众覆盖多头头寸
    {
        {返回POS; }
        集合{抛出新NotSupportedException异常(); }
    }    公共覆盖无效写入(字节[]缓冲区,诠释抵消,诠释计数)
    {
        POS + =计数;
        wrapped.Write(缓冲区,偏移数);
    }    公共覆盖无效的flush()
    {
        wrapped.Flush();
    }    保护覆盖无效的Dispose(BOOL处置)
    {
        wrapped.Dispose();
        base.Dispose(处置);
    }    //规定的所有其他方法可以抛出NotSupportedException异常
}

使用这个,下面的code会写一个ZIP压缩到的OutputStream

 使用(VAR的OutputStream =新PositionWrapperStream(Response.OutputStream))
使用(VAR存档=新的ZipArchive(OutputStream的,ZipArchiveMode.Create,FALSE))
{
    变种条目= archive.CreateEntry(文件名);    使用(VAR作家=新的StreamWriter(entry.Open()))
    {
        writer.WriteLine(关于这个包的信息。);
        writer.WriteLine(========================);
    }
}

I've been trying to get the "new" ZipArchive included in .NET 4.5 (System.IO.Compression.ZipArchive) to work in a ASP.NET site. But it seems like it doesn't like writing to the stream of HttpContext.Response.OutputStream.

My following code example will throw

System.NotSupportedException: Specified method is not supported

as soon as a write is attempted on the stream.

The CanWrite property on the stream returns true.

If I exchange the OutputStream with a filestream, pointing to a local directory, it works. What gives?

ZipArchive archive = new ZipArchive(HttpContext.Response.OutputStream, ZipArchiveMode.Create, false);

ZipArchiveEntry entry = archive.CreateEntry("filename");

using (StreamWriter writer = new StreamWriter(entry.Open()))
{
    writer.WriteLine("Information about this package.");
    writer.WriteLine("========================");
}

Stacktrace:

[NotSupportedException: Specified method is not supported.]
System.Web.HttpResponseStream.get_Position() +29
System.IO.Compression.ZipArchiveEntry.WriteLocalFileHeader(Boolean isEmptyFile) +389
System.IO.Compression.DirectToArchiveWriterStream.Write(Byte[] buffer, Int32 offset, Int32 count) +94
System.IO.Compression.WrappedStream.Write(Byte[] buffer, Int32 offset, Int32 count) +41

解决方案

Calbertoferreira's answer has some useful information, but the conclusion is mostly wrong. To create an archive, you don't need seek, but you do need to be able to read the Position.

According to the documentation, reading Position should be supported only for seekable streams, but ZipArchive seems to require this even from non-seekable streams, which I think is a bug.

So, all you need to do to support writing ZIP files directly to OutputStream is to wrap it in a custom Stream that supports getting Position. Something like:

class PositionWrapperStream : Stream
{
    private readonly Stream wrapped;

    private int pos = 0;

    public PositionWrapperStream(Stream wrapped)
    {
        this.wrapped = wrapped;
    }

    public override bool CanSeek { get { return false; } }

    public override bool CanWrite { get { return true; } }

    public override long Position
    {
        get { return pos; }
        set { throw new NotSupportedException(); }
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        pos += count;
        wrapped.Write(buffer, offset, count);
    }

    public override void Flush()
    {
        wrapped.Flush();
    }

    protected override void Dispose(bool disposing)
    {
        wrapped.Dispose();
        base.Dispose(disposing);
    }

    // all the other required methods can throw NotSupportedException
}

Using this, the following code will write a ZIP archive into OutputStream:

using (var outputStream = new PositionWrapperStream(Response.OutputStream))
using (var archive = new ZipArchive(outputStream, ZipArchiveMode.Create, false))
{
    var entry = archive.CreateEntry("filename");

    using (var writer = new StreamWriter(entry.Open()))
    {
        writer.WriteLine("Information about this package.");
        writer.WriteLine("========================");
    }
}

这篇关于使用写入ZipArchive HttpContext的的OutputStream的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆