如何添加一个流

本文关键字:一个 添加 何添加 | 更新日期: 2023-09-27 18:15:24

我正在从数据库中加载blobs作为字节数组,并将它们放在内存流中,以便我可以将它们加载到xmldocument中进行解析。

然而,有些blob有多个根节点,这会导致解析器崩溃。

我的解决方案是创建一个包含整个blob的新根节点。

我可以添加到结尾,但是我不知道如何添加到开头。

如何添加到流?



我费了好大劲才把它修好。我提取的"XML"不是正确的XML,我一直不得不添加越来越多的正则表达式来删除XmlDocument加载之前的坏XML。我最终使用htmllagilitypack解析出有效的XML部分,并将它们放入它们自己的XML文档中。不是最好的解决方案,但它有效。

如何添加一个流

由于您已经从DB中获得了byte[]数组,因此在数组前后写入更多字节到内存流应该很容易:

// bytes from db
byte[] multipleNodes = Encoding.UTF8.GetBytes("<first>..</first><second>..</second><third>..</third>");
using (var ms = new MemoryStream())
{
    // write opening tag
    byte[] newRoot = Encoding.UTF8.GetBytes("<newRoot>");
    ms.Write(newRoot, 0, newRoot.Length);
    ms.Write(multipleNodes, 0, multipleNodes.Length);
    // write opening tag
    byte[] closeNewRoot = Encoding.UTF8.GetBytes("</newRoot>");
    ms.Write(closeNewRoot, 0, closeNewRoot.Length);
    // reset cursor position before pass it to xmldoc
    ms.Position = 0;
    var xml = new XmlDocument();
    xml.Load(ms);
    Console.WriteLine(xml.InnerXml);
}

但是由于XmlDocument也提供LoadXml(str),我觉得操纵字符串应该是更直接的解决方案:

// bytes from db
byte[] multipleNodes = Encoding.UTF8.GetBytes("<first>..</first><second>..</second><third>..</third>");
string stringFromBlob = Encoding.UTF8.GetString(multipleNodes);
string withRootNode = string.Format("<newRoot>{0}</newRoot>", stringFromBlob);
var xml = new XmlDocument();
xml.LoadXml(withRootNode);
Console.WriteLine(xml.InnerXml);

你不能直接。这导致两个选项:

  • 在加载blobs之前在内存流中写入一个开始标签
  • 创建第二个内存流,写入开始标签,将第一个内存流复制到第二个内存流中。

这是我使用的:

public class CompositeStream : FileStream
{
    Stream[] childStreams;
    int currentStreamIndex = 0;
    Stream currentStream;
    public long totalStreamRead{get; private set;}
    public CompositeStream(string pre, FileStream s_file, string post)
        : base(s_file.SafeFileHandle, FileAccess.Read)
    {
        totalStreamRead = 0;
        MemoryStream s_pre = new MemoryStream();
        MemoryStream s_post = new MemoryStream();
        byte[] b_pre = Encoding.UTF8.GetBytes(pre);
        s_pre.Write(b_pre, 0, b_pre.Length);
        s_pre.Flush();
        s_pre.Seek(0, SeekOrigin.Begin);
        byte[] b_post = Encoding.UTF8.GetBytes(post);
        s_post.Write(b_post, 0, b_post.Length);
        s_post.Flush();
        s_post.Seek(0, SeekOrigin.Begin);
        childStreams = new Stream[] { s_pre, s_file, s_post };
        currentStream = childStreams[currentStreamIndex++];
    }
    public override int Read(byte[] buffer, int offset, int count)
    {
        int totalBytesRead = 0;
        while (count > 0)
        {
            // Read what we can from the current stream
            int numBytesRead = currentStream.Read(buffer, offset, count);
            totalBytesRead += numBytesRead;
            count -= numBytesRead;
            offset += numBytesRead;
            // If we haven't satisfied the read request, 
            // we have exhausted the current stream.
            // Move on to the next stream and loop around to read more data.
            if (count > 0)
            {
                // If we run out of child streams to read from...
                if (currentStreamIndex >= childStreams.Length)
                    break; //get out
                currentStream.Close();
                currentStream = childStreams[currentStreamIndex++];
            }
        }
        totalStreamRead += totalBytesRead;
        return totalBytesRead;
    }
}

一种干净的方法是实现一个CompositeStreamReader,它将接受一些流,然后按顺序读出它们。

在https://web.archive.org/web/20100721082808/http://blogs.msdn.com/b/paolos/archive/2010/04/08/how-to-boost-message-transformations-using-the-xslcompiledtransform-class-extended.aspx有一个实现,您可以适应,但您可以使用更简单的东西。