简体   繁体   English

XmlDocument无法从ZipArchive条目加载流

[英]XmlDocument fails to load stream from ZipArchive entry

I have a zip file that contains an XML file. 我有一个包含XML文件的zip文件。 Using the System.IO.Compression ZipArchive I open the XML file as a Stream (actually a DeflateStream): 使用System.IO.Compression ZipArchive,我将XML文件作为流(实际上是DeflateStream)打开:

Stream xmlStream = null;
using (ZipArchive archive = ZipFile.Open(destPath, ZipArchiveMode.Read))
{
    xmlStream = archive.GetEntry(fileNameXml).Open();
}

Now I can read from the stream using the Stream.Read method: 现在,我可以使用Stream.Read方法从流中读取:

// This works
byte[] buffer = new byte[10];
int tmp = xmlStream.Read(buffer, 0, 10);

What I really want to do, however, is to load the data into an XmlDocument like this: 但是,我真正想要做的是将数据加载到XmlDocument中,如下所示:

XmlDocument xmlDoc = new XmlDocument();
// This throws 'NotSupportedException'
xmlDoc.Load(xmlStream);

But this throws a NotSupportedException with the message "This stream from ZipArchiveEntry does not support reading." 但这会引发NotSupportedException并显示消息“来自ZipArchiveEntry的此流不支持读取”。

I could of course extract the XML file and open the file, but reading from the stream directly seems to me like a much nicer solution - if I could get it to work! 我当然可以提取XML文件并打开文件,但是对我来说,直接从流中读取似乎是一个更好的解决方案-如果我可以使它工作的话!

可能是因为它被包装在一个using中,所以当您实际从流中读取它时,它已经被丢弃了。

This happens when you have a method like this: 当您使用如下方法时,就会发生这种情况:

    public Stream OpenStream(string filePath)
    {
        using(var zipFile = ZipFile.OpenRead(filePath))
        {
            var entry = zipFile.GetEntry("entryName");
            return entry.Open();
        }
    }

And are using it like this: 并像这样使用它:

    using(var stream = OpenStream(filePath))        
    {
        // NotSupportedException: This stream from ZipArchiveEntry does not support reading.
        // because zipFile is already disposed before reading the entry stream
    }

What we really want to happen is to Dispose of the zipFile at the same time we dispose of the Stream returned by entry.Open() . 我们真正希望发生的是Dispose的的zipFile在我们处置的同时Stream通过返回entry.Open() There's a few approaches to this and depending on your design it might be simple. 有几种解决方法,根据您的设计,它可能很简单。 One of those approaches is to create a wrapper class around the stream and dispose of both streams at the same time. 这些方法之一是围绕流创建包装类,并同时处置两个流。

public class OnDisposeStream : Stream
{
    private readonly Stream _stream;
    private readonly Action _onDispose;

    public OnDisposeStream(Stream stream, Action onDispose)
    {
        _stream = stream;
        _onDispose = onDispose;
    }

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

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

    public override long Seek(long offset, SeekOrigin origin)
    {
        return _stream.Seek(offset, origin);
    }

    public override void SetLength(long value)
    {
        _stream.SetLength(value);
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        return _stream.Read(buffer, offset, count);
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        _stream.Write(buffer, offset, count);
    }

    public override bool CanRead => _stream.CanRead;
    public override bool CanSeek => _stream.CanSeek;
    public override bool CanWrite => _stream.CanWrite;
    public override long Length => _stream.Length;

    public override long Position
    {
        get { return _stream.Position; }
        set { _stream.Position = value; }
    }
}

Then change our original method like this: 然后像这样更改我们的原始方法:

    public Stream OpenStream(string filePath)
    {
        var zipFile = ZipFile.OpenRead(filePath);
        var entry = zipFile.GetEntry("entryName");
        return new OnDisposeStream(entry.Open(), () => zipFile.Dispose());
    }        

Hopefully that'll help someone one day. 希望有一天能对某人有所帮助。

OK - figured out a workaround that I can live with. 好的-找到了我可以接受的解决方法。

I don't know how the XML document is trying to read the DeflateStream, since all ways I have tried to read from the stream manually has worked. 我不知道XML文档是如何尝试读取DeflateStream的,因为我尝试从流中手动读取的所有方法都有效。

I used this workaround to keep the data in a stream and load that stream into my XmlDocument: 我使用此变通办法将数据保留在流中并将该流加载到XmlDocument中:

MemoryStream readerStream = new MemoryStream();
xmlStream.CopyTo(readerStream);
readerStream.Position = 0;
xmlDoc.Load(readerStream);

If anyone has an explanation for the strange behavior exhibited by the DeflateStream or has a better way to get the data from the DeflateStream into the xml document I would be interested in hearing that 如果有人对DeflateStream表现出的奇怪行为有一个解释,或者有更好的方法将数据从DeflateStream获取到xml文档中,我很想听听

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Ziparchive:如何从ziparchive关闭创建的条目 - Ziparchive: How to close the created entry from ziparchive 从 stream 加载 XmlDocument 时缺少根元素 - Root element is missing when load XmlDocument from a stream XmlDocument-从字符串加载? - XmlDocument - load from string? XmlDocument.Load失败,LoadXml工作: - XmlDocument.Load fails, LoadXml works: c# 如何将 memory stream 加载到没有 BOM 的 xmldocument? (我的 memory stream 是从没有 BOM 的 XMLTextWriter 生成的) - c# How to load a memory stream to an xmldocument without BOM? (My memory stream is generated from XMLTextWriter without BOM) 如何从 XmlDocument() 上的 URL 加载 XML - How to load XML from URL on XmlDocument() XmlDocument类无法加载包含具有C#代码的节点的文件 - XmlDocument class fails to load a file that contains a node with C# code WinRT / Metro / WSA问题为WebView提供了来自ZipArchive的流 - WinRT/Metro/WSA issue providing WebView with stream from ZipArchive ZipArchive 从不可搜索的流中读取而不缓冲到内存 - ZipArchive Read From Unseekable Stream Without Buffering to Memory SslStream上的.NET XmlReader-从流中读取多个XML-使其成为XmlDocument - .NET XmlReader on SslStream - reading multiple XMLs from stream - obtatining XmlDocument
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM