4

我正在读取一个非常大的 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;
            }
        }
    }
}

在处理过程中,我得到了一个无效的字符异常:

' ', hexadecimal value 0x19, is an invalid character. Line 655, position 45.

鉴于不允许在 try-catch 中产生 return - 在发生错误的情况下,有什么好方法可以简单地中止当前 Xml 文档的处理(并完成枚举)?

try/finally 不好 - 因为异常会破坏整个 IEnumerable 的处理。

我无法对文件执行任何预处理。

4

2 回答 2

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;
}

不过,您还应该处理其他可能的异常,但不确定您是否正在处理从中调用它的那些异常。它并不优雅,但我不确定你的限制是什么(例如,没有预处理)

于 2013-09-23T13:21:15.897 回答
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
   }
}
于 2016-05-15T11:17:36.607 回答