我正在阅读一个非常大的XML文件,我必须将其作为流读取,如下所示:
public IEnumerable<something> GetStuff()
{
foreach(var gzipStream in GetGZips())
{
using (var reader = XmlReader.Create(gzipStream, new XmlReaderSettings{ CheckCharacters = false }))
{
reader.MoveToContent();
while (reader.Read()) //<-- Exception here
{
//Do stuff
yield return something;
}
}
}
}
我得到了一个无效的char异常,处理过程中的一部分:
' ', hexadecimal value 0x19, is an invalid character. Line 655, position 45.
鉴于你不允许在try-catch中产生回报 - 在出现错误的情况下,简单地中止当前Xml doc(并完成Enumeration)的处理有什么好方法?
try / finally并不好 - 因为异常会破坏整个IEnumerable的处理。
我无法对文件执行任何预处理。
答案 0 :(得分:1)
如果你真的无法进行任何预处理,并且绝对必须在解析XML时生成枚举,那么如果用以下内容替换while循环呢?
bool IsMoreXml = true;
while (IsMoreXml)
{
var ValuesRead = null; //not sure what you're reading
try
{
IsMoreXml = reader.Read();
if(!IsMoreXml) break;
//Do Stuff
ValuesRead = whateverwereadfromxml;
}
catch (XmlException ex)
{
//do what you gotta do
break;
}
if(ValuesRead != null)
yield return ValuesRead;
}
您应该处理其他可能的异常,但不确定您是否正在处理从中调用它的那些异常。它不优雅,但后来我不确定你的限制是什么(例如,没有预处理)
答案 1 :(得分:0)
我只是处理同样的事情。我知道这已经过时了,但我想我会把它放在这里作为参考。
我打算提出一个要点,但我认为看看GitHub上的提交会更有帮助。
https://github.com/DewJunkie/Log2Console/commit/fb000c0a97c6762b619d213022ddc750bd9254ae 如果您使用winmerge比较之前的版本,您将更清楚地了解更改。
虽然你无法在try catch中获得yield返回,但你可以使用另一个返回单个解析实例的函数。 try catch将在第二个函数中。我使用正则表达式将日志拆分为单个记录。我假设即使在一个大文件中,单个记录仍然适合几KB的缓冲区。我还想象RegEx会有一些开销,但我主要担心的是丢失数据。
我实际上花了几个小时写一个解析器,当我测试时,我意识到解析器的核心是这个正则表达式,我实际上甚至不需要其余的。
TLDR;
//旧方法,非常类似于你的方法
while(!xmlreader.eof){xmlreader.read();}
//新方法
IEnumerable<Foo> ParseFile(stream){
foreach(var match in Regex.Matches(xmlText,$"<(/?)\\s*(XML_RECORD_ELEMENT)[^<>]*(/?)>")
{/*logic to split xml based on matches.
working code is in the above commit. Not too long, but too long for MD. */
yield return ParseXmlFragment(xmlFragment);
...}
}
Foo ParseXmlFragment(string xmlFragment)
{
Foo newFoo = new Foo();
try{//xmlreader here to parse fragment}
catch(ex)
{
// handle ex if possible here. If not possible, you now have the complete text of the unparsable fragment, which you can correct and try again.
throw; // if you want to halt execution, or you can continue
}
}