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