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

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

问题描述

我一直试图让 .NET 4.5 (System.IO.Compression.ZipArchive) 中包含的新"ZipArchive 在 ASP.NET 站点中工作.但它似乎不喜欢写入 HttpContext.Response.OutputStream 的流.

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: 不支持指定的方法

System.NotSupportedException: Specified method is not supported

一旦尝试写入流.

流上的 CanWrite 属性返回 true.

The CanWrite property on the stream returns true.

如果我将 OutputStream 与指向本地目录的文件流交换,它就可以工作.什么给?

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("========================");
}

堆栈跟踪:

[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

推荐答案

注意: 这已在 .Net Core 2.0 中修复.我不确定 .Net Framework 的修复状态是什么.

Note: This has been fixed in .Net Core 2.0. I'm not sure what is the status of the fix for .Net Framework.

Calbertoferreira 的回答提供了一些有用的信息,但结论大多是错误的.要创建存档,您不需要搜索,但您需要能够读取 Position.

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.

根据文档,阅读Position 应该只支持可查找的流,但 ZipArchive 似乎甚至需要来自不可查找的流,即 一个错误.

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 is a bug.

因此,支持将 ZIP 文件直接写入 OutputStream 所需要做的就是将其包装在支持获取 Position 的自定义 Stream 中>.类似的东西:

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 long 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
}

使用这个,下面的代码将一个 ZIP 文件写入 OutputStream:

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("========================");
    }
}

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

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