当xml文件的行数超过int.Maxvalue时,如何获取行号

6

我无法在一个将近300GB的XML文件中获取行号。IXmlLineInfo.LineNumber是一个int32类型,当超过int.MaxValue时会返回一个负数。使用int或long都无法存储行号-已尝试使用两种类型。Xmlreader能够读取到eof。 使用.NET 2.0和最新版本也是使用int32类型。

public void ReadLines()
    {
        long readcounter = 0;
        long linenumber = 0;
        fname = "I:\\XML Files\\europe-latest.osm";
        XmlReaderSettings settings = new XmlReaderSettings();
        settings.ProhibitDtd = false;
        settings.XmlResolver = null;
        XmlReader reader = XmlReader.Create(fname, settings);

        IXmlLineInfo lineInfo = ((IXmlLineInfo)reader);
        try
        {
            while (reader.Read())
            {
                linenumber = lineInfo.LineNumber;
                readcounter++;
                if (readcounter % 1000000 == 0) Console.WriteLine(linenumber.ToString());
            }
        }
        catch (XmlException ex)
        {
            Console.WriteLine(ex.Message);
            Console.ReadLine();
        }
        finally
        {
            reader.Close();
            Console.WriteLine(DateTime.Now.ToLongTimeString());
        }

    }

10
我的天啊,一个300GB的XML文件?你确定吗? - tnw
7
也许你应该停止担心获取行号的问题,而是关注于导致这个XML文件变得如此庞大的原因。 - mason
1
我会考虑使用XmlReaderSettings.LineNumberOffset属性并在Int64中自己计算行数。 - ClickRick
2
你可以在駱駝背上放的稻草是有限度的。 - TyCobb
1
Mason - 客户文件,你可能会惊讶于这样的大文件是多么普遍。整个维基百科都可以在巨大的XML文件中获得。大多数政府机构都有大型文件。 - user204427
显示剩余3条评论
2个回答

1

你可以尝试的方法不多:

1)使用System.Numerics.BigInteger存储实际行号-在每次操作后检查行号是否比之前更小,同时在BigInteger中存储实际行号。在非常大的文件中,它可能会溢出并变得比之前更大(例如,在几个内部增量中读取了50亿行元素后):

var actualLine = new System.Numerics.BigInteger(0);

Int32 lastInt32Line = lineInfo.LineNumber;

// Some Xml reading

Int32 diff = lineInfo.LineNumber - lastLine;

// If an overflow has happened - add overflow
if (diff >= 0)
    actualLine += (new BigInteger(Int32.MaxValue)) * 2 - diff;
else // Everything is normal - add the diff
    actualLine += diff;

真正可能的问题是,尽管您正确地存储了行号,但 XmlReader 的内部可能开始崩溃。在我看来,checked 整数算术代码应该是默认的,而不是现在的未检查代码 - 当发生溢出时,如果没有明确说明,那么该类将被损坏。

2)重新组织数据存储以更分散的方式处理数据。
3)编写自己的 XmlReader,使用 BigInteger。


我接受这个答案,主要是因为我同意我没有太多可以尝试的东西。 - user204427

1

经过使用dotpeek进行一些调查,似乎问题深深地植根于内部XmlTextReaderImpl类(这应该是您正在使用的实际阅读器类型)和它正在使用的内部类型:

internal struct LineInfo
{
    internal int lineNo;
    internal int linePos;
    // ...
}

如果您想尽可能少地工作,我建议您获取.NET源代码,通过复制XmlTextReaderImpl(和所有相关的内部类型),将所有行号int替换为BigInteger,创建自己的Xml reader。如果您想隐藏类型,您可能需要创建一个名为IXmlBigLineInfo的接口或类似的东西,并使用它代替IXmlLineInfo
希望这可以帮到您。

我正在使用 .net 2.0。在 2.0 版本中,XmlTextReader 不完全符合 XML 标准,因此我无法使用它。例如,它不会规范化行尾或在读取未引用的命名实体时抛出异常。也许这个问题在 4.5 版本中得到了修复,但我怀疑这一点,因为 XmlReader 类是微软推荐的类。也许这并不适用于 XmlTextReaderImpl,并且可以轻松测试它。 - user204427
当您调用XmlReader.Create时,将返回XmlTextReaderImpl。请检查reader.GetType() - gwiazdorrr
不确定长期使用该类是否好。在MSDN XML论坛上找到了这个:TextReaderImpl是一个内部类,它实现了XmlReader“接口”。根据读取器的设置,当您调用XmlReader.Create时,可能会得到此类的实例。该类不是公共的,因为它继承自XmlReader类,其所有功能都通过XmlReader类公开。您不应基于XmlReader的实际实现类做出任何决策,因为我们将来可能会选择更改它。谢谢, Vitek Karas [MSFT] - user204427
看一下XmlReader.Create的作用,对于你的情况它将始终返回XmlTextReaderImpl。如果你传递一个现有的读取器等等,它可能会返回不同的东西,但这不是你的情况。我建议你试一试——这将不到一天的工作量。 - gwiazdorrr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接