C# 将多个XML文件合并到单个流中

C# 将多个XML文件合并到单个流中,c#,.net,C#,.net,我有数百个XML文件,它们一个接一个地被处理。我想对文件中的数据应用其他现有代码。但是,编写该代码的目的是希望看到单个文件或表示单个文件的流 我看了一眼 然而,Marc的答案中给出的StreamEnumerator要求一次打开所有相关文件的流。考虑到我的案例中有大量文件,这似乎不是一个好方法 现有代码如下所示使用流: XmlReader reader = XmlReader.Create(xmlStream); 有没有更好的方法将许多文件组合成一个流?好吧,我将编写自己的类来扩展System

我有数百个XML文件,它们一个接一个地被处理。我想对文件中的数据应用其他现有代码。但是,编写该代码的目的是希望看到单个文件或表示单个文件的流

我看了一眼

然而,Marc的答案中给出的
StreamEnumerator
要求一次打开所有相关文件的流。考虑到我的案例中有大量文件,这似乎不是一个好方法

现有代码如下所示使用流:

XmlReader reader = XmlReader.Create(xmlStream);

有没有更好的方法将许多文件组合成一个流?

好吧,我将编写自己的类来扩展System.IO.stream,并通过重载CanRead和Read方法按需加入这些流。类似这样的内容(只是一个概念存根,您需要对代码进行微调):

使用系统;
使用系统诊断;
使用System.IO;
使用System.Xml;
命名空间控制台应用程序1
{
公共类CombinedXmlStream:Stream
{
私有流currentStream、startStream、endStream;
私有字符串[]文件;
私有int currentFile=-2;
private bool endreach=false;
私有静态流到流(字符串str)
{
MemoryStream stream=新的MemoryStream();
StreamWriter writer=新StreamWriter(流);
writer.Write(str);
writer.Flush();
流位置=0;
回流;
}
public CombinedXmlStream(字符串开始、字符串结束、参数字符串[]文件)
{
this.files=文件;
startStream=ToStream(启动);
endStream=ToStream(结束);
}
公共重写bool CanRead{get{return true;}}
公共覆盖布尔CanSeek{get{return false;}}
公共重写bool可以写入{get{return false;}}
公共重写长长度{get{throw new NotImplementedException();}}
公共重写长位置{get{return 0;}set{}
公共重写void Flush(){抛出新的NotImplementedException();}
公共重写长寻道(长偏移量,SeekOrigin原点){throw new NotImplementedException();}
public override void SetLength(长值){throw new NotImplementedException();}
公共重写无效写入(字节[]缓冲区,整数偏移量,整数计数){抛出新的NotImplementedException();}
公共重写整型读取(字节[]缓冲区、整型偏移量、整型计数)
{
doSwitching();
int output=currentStream.Read(缓冲区、偏移量、计数);
如果(输出==0)
{
剂量切换(真);
如果(currentStream!=null)
{
返回读取(缓冲区、偏移量、计数);
}
}
返回输出;
}
专用无效数据切换(布尔力=假)
{
if(force | | currentStream==null | | |!currentStream.CanRead)
{
如果(currentStream!=null)
{
currentStream.Close();
currentStream=null;
}
currentFile++;
如果(当前文件==-1)
{
currentStream=startStream;
}
else if(currentFile>=files.Length&&!endreach)
{
currentStream=endStream;
endreach=true;
}
否则,如果(!endreach)
{
currentStream=新文件流(文件[currentFile],FileMode.Open);
}
}
}
}
班级计划
{
静态void Main(字符串[]参数)
{
Debug.WriteLine(“测试我”);
使用(XmlReader=XmlReader.Create(新组合的xmlstream(“,”,@“D:\test.xml”,“@“D:\test2.xml”))
{
//reader.MoveToContent();
while(reader.Read())
{
if(reader.NodeType==XmlNodeType.Element)
{
Debug.WriteLine(“节点:“+reader.Name”);
}
}
}
}
}
}

该方法似乎还可以。我认为您必须在流的开头添加“-”,在添加每个文件时删除“”并在流的末尾添加“”。我试图避免同时打开数百个或数千个流。该方法包括创建一个xmlStream供现有代码使用。运行一个单独的线程在流上写入数据,方法是在要合并的文件中读取一个adter另一个adter。启动单独的线程后,执行“XmlReader reader=XmlReader.Create(xmlStream);”@HenkHolterman:我正在尝试首先找到一个通用解决方案,然后将对其进行调整以无缝地组合XML数据。似乎只有当Read()请求不跨越两个物理文件之间的边界时,这才有效。您似乎还假设每个流都有一个CanRead调用,这似乎不太可能。您检查过了吗?每次读取后都会多次调用CanRead(通过简单地扩展FileStream并重写这两个方法以及使用断点和/或调试控制台输出来测试您自己)。接下来,边界不是问题,但在本例中,您是对的。但是,您可以再次忽略CanRead并执行Read方法中的所有逻辑。原则不变:创建自己的流实现,在正确的时间合并文件。@EricJ。用完整的工作概念证明重新编辑了我的示例。创建两个XML文件(但它们不能有序言——这只是POC,所以您需要自己添加一个),这将组合这些流。不必担心文件之间的边界-在到达EOF之前调用Read,然后进行切换。还要注意的是,这个c
using System;
using System.Diagnostics;
using System.IO;
using System.Xml;

namespace ConsoleApplication1
{

    public class CombinedXmlStream : Stream
    {
        private Stream currentStream, startStream, endStream;
        private String[] files;
        private int currentFile = -2;
        private bool endReached = false;

        private static Stream ToStream(String str)
        {
            MemoryStream stream = new MemoryStream();
            StreamWriter writer = new StreamWriter(stream);
            writer.Write(str);
            writer.Flush();
            stream.Position = 0;
            return stream;
        }

        public CombinedXmlStream(String start, String end, params String[] files)
        {
            this.files = files;
            startStream = ToStream(start);
            endStream = ToStream(end);

        }

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

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

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

        public override long Length { get { throw new NotImplementedException(); } }

        public override long Position { get { return 0; } set { } }

        public override void Flush() { throw new NotImplementedException(); }

        public override long Seek(long offset, SeekOrigin origin) { throw new NotImplementedException(); }

        public override void SetLength(long value) { throw new NotImplementedException(); }

        public override void Write(byte[] buffer, int offset, int count) { throw new NotImplementedException(); }

        public override int Read(byte[] buffer, int offset, int count)
        {
            doSwitching();

            int output = currentStream.Read(buffer, offset, count);

            if (output == 0)
            {
                doSwitching(true);
                if (currentStream != null)
                {
                    return Read(buffer, offset, count);
                }
            }

            return output;
        }

        private void doSwitching(bool force = false)
        {
            if (force || currentStream == null || !currentStream.CanRead)
            {
                if (currentStream != null)
                {
                    currentStream.Close();
                    currentStream = null;
                }

                currentFile++;
                if (currentFile == -1)
                {
                    currentStream = startStream;
                }
                else if (currentFile >= files.Length && !endReached)
                {
                    currentStream = endStream;
                    endReached = true;
                }
                else if (!endReached)
                {
                    currentStream = new FileStream(files[currentFile], FileMode.Open);
                }
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Debug.WriteLine("Test me");
            using (XmlReader reader = XmlReader.Create(new CombinedXmlStream("<combined>", "</combined>", @"D:\test.xml", @"D:\test2.xml")))
            {
                //reader.MoveToContent();
                while (reader.Read())
                {
                    if (reader.NodeType == XmlNodeType.Element)
                    {
                        Debug.WriteLine("Node: " + reader.Name);
                    }
                }
            }
        }
    }
}