![](/img/trans.png)
[英]How to read the nodes of xml file in c#, where the xml file is the combination of 2 xml file data?
[英]How to read XML data from the header of a mixed xml/binary file in C#
我的任务是为具有以下规范的文件格式编写阅读器:
29
字节分隔(ASCII表中的组分隔符)。 我看到两种读取文件xml部分的方法。 第一个是逐字节构建字符串,直到找到分隔符。
另一种是使用一些库来解析xml并自动检测格式正确的xml的结尾。
问题是:在XML中最后一个结束标记之后,是否有任何.NET库会自动停止?
(或者,有人可以建议一种更明智的方式来读取这种文件格式吗?)
更新:根据彼得·杜尼奥(Peter Duniho)的回答,进行了一些细微修改,我最终做到了这一点(尽管没有经过完全的单元测试,但它仍然有效)。
int position = 0;
MemoryStream ms;
using (FileStream fs = File.OpenRead("file.xml"))
using (ms = new MemoryStream())
{
int current;
while ((current = fs.ReadByte()) > 0)
{
position++;
if (current == 29)
break;
ms.WriteByte((byte)current);
}
}
var xmlheader = new XmlDocument();
xmlheader.LoadXml(Encoding.UTF8.GetString(ms.ToArray()));
虽然“读到结束标签”听起来很吸引人,但是您需要有一个解析器,该解析器最终不会缓冲所有数据。
我会将所有数据读取到byte[]
,然后在其中搜索分隔符-然后可以将二进制数据拆分为两个,并适当地解析每个部分。 我将完全以二进制形式工作,而不涉及任何字符串-您可以使用new MemoryStrem(byte[], int, int)
为每个部分创建一个MemoryStream
,然后将其传递给XML解析器以及最终的解析器。 这样,您无需担心处理UTF-8,也不必担心XML的更高版本是否不使用UTF-8,等等。
所以像这样:
byte[] allData = File.ReadAllBytes(filename);
int separatorIndex = Array.IndexOf(allData, (byte) 29);
if (separatorIndex == -1)
{
// throw an exception or whatever
}
var xmlStream = new MemoryStream(allData, 0, separatorIndex);
var lastPartStream = new MemoryStream(
allData, separatorIndex + 1, allData.Length - separatorIndex - 1);
根据您提供的信息,仅搜索具有值29的字节就可以了,因为XML是UTF8,只有文件中存在字符代码点29的情况下,才出现值29的字节。 现在,我猜它可能存在,但这会令人惊讶,因为它在ASCII值的控制字符范围内。
根据XML 1.0规范:
字符:: =#x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] / *任何Unicode字符,但代理块FFFE和FFFF除外。 * /
尽管注释暗示29在XML文件中将是有效的代码点(因为它本身是有效的Unicode字符),但我认为实际的语法是规范性的。 也就是说,它特别排除了代码点32以下的字符,但制表符,换行符和回车符除外,因此29 不是有效的XML字符(就像Jon Skeet所说的那样)。
就是说,如果没有完整的输入说明,就不能排除这种可能性。 因此,如果您真的想安全起见,则必须继续解析XML,以期为根元素找到合适的结束标记。 然后,您可以搜索字节29(因为在结束标记后可能会有空白),以标识二进制数据的起始位置。
(注意:索要一个库是“题外话”。但是,您可能可以使用XmlReader
来执行此操作,因为它是迭代运行的;即,您可以在达到最终关闭标记之后以及之前终止其操作。它开始抱怨发现无效的XML,但这取决于XmlReader
可能进行的缓冲;如果它缓冲了结束标记之后的其他数据,则基础流的位置将超过29个字节,这使查找变得更加困难坦白地说,仅搜索29字节似乎是一种方法。
您可以像这样在标头中搜索29个字节(警告:浏览器代码...未编译,未经测试):
MemoryStream xmlStream = new MemoryStream();
using (FileStream stream = File.OpenRead(path))
{
int offset = 0, bytesRead = 0;
// arbitrary size...whatever you think is reasonable would be fine
byte[] buffer = new byte[1024];
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
{
bool found = false;
for (int i = 0; i < bytesRead; i++)
{
if (buffer[i] == 29)
{
offset += i;
found = true;
xmlStream.Write(buffer, 0, i - 1);
break;
}
}
if (found)
{
break;
}
offset += bytesRead;
xmlStream.Write(buffer, 0, bytesRead);
}
if (bytesRead > 0)
{
// found byte 29 at offset "offset"
xmlStream.Position = 0;
// pass "xmlStream" object to your preferred XML-parsing API to
// parse the XML, or just return it or "xmlStream.ToArray()" as
// appropriate to the caller to let the caller deal with it.
}
else
{
// byte 29 not found!
}
}
编辑:
我已经更新了上面的代码示例,将其写入MemoryStream
对象,以便一旦找到字节29的值,就可以准备进行XML解析的所有流。 当然,如果您确实需要,我敢肯定您可以自己添加。 无论如何,很明显,无论有无此功能,您都可以修改代码以适合您的需求。
(搜索时写入MemoryStream
存在明显的危险:如果您未找到字节29的值,则会在内存中看到整个文件的完整副本,建议您这样做宁愿避免。但是考虑到这是错误的情况,那可能没问题)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.