使用写入ZipArchive HttpContext的的OutputStream [英] Writing to ZipArchive using the 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 ofHttpContext.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, butZipArchive
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 customStream
that supports gettingPosition
. 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屋!