1

私はC#でパーサーを使用して、複数のxmlファイルからデータを取得し、それらを自分のデータベースに配置しています。

今、私は動作するこのコードを持っています:

 List<CaseFile> caseFiles =
            (
                from e in XDocument.Load(xmlDoc).Root.Elements("application-information").Elements("file-segments").Elements("action-keys").Elements("case-file")
                select new CaseFile
                { (......)
}).toList();

これにより、CaseFileオブジェクトのリストが作成され、後で他のメソッドに送信して、データをデータベースに配置します。これに伴う問題は、一度に多くのファイルを解析する必要があることです。1GBから200 MB以上のファイルがあるため、大量のメモリが必要になります。

ステートメントを変更して、見つかったすべてのCaseFileについて、最初にそれらの完全なリストを作成する代わりに、他のメソッドに即座に送信する方法はありますか?

4

3 に答える 3

3

XDocument.Load最初にファイル全体をメモリにロードします。要素をすばやく検索するにIEnumerableは、CaseFire オブジェクトを返し、ノードごとにファイルを読み取るために使用します (ノードが at のみでXmlReaderあると仮定します。それ以外の場合は、ここでさらにロジックが必要になります)。case-fileroot/application-information/file-segments/action-keys

static IEnumerable<CaseFile> FindCaseFiles(string uri)
{
    using (XmlReader reader = XmlReader.Create(uri))
    {
        reader.MoveToContent();

        while (reader.Read())
        {
            switch (reader.NodeType)
            {
                case XmlNodeType.Element:
                    if (reader.Name == "case-file")
                    {
                        XElement el = XElement.ReadFrom(reader) as XElement;
                        if (el != null)
                            yield return new CaseFile() {...};
                    }
                    break;
            }
        }
    }
}

使用法:

foreach(CaseFile file in FindCaseFiles(path_to_xml))
{
    // we have CaseFile here immediately after it found in xml file
}
于 2012-12-10T20:19:33.193 に答える
0

ここでの問題は、LINQ-Expressionの結果でToListを呼び出すことです。これにより、すべての値が列挙され、すべてがメモリに書き込まれます。LINQ-Expression自体は値を列挙しません。IEnumerableを返すだけです。LINQ-ExpressionによってCaseFile-objectsは作成されません。

LINQ-Expressionの結果をループするだけで、次々に値が読み取られます。

var caseFiles = from e in XDocument.Load(xmlDoc).Root.
                    Elements("application-information").
                    Elements("file-segments").
                    Elements("action-keys").
                    Elements("case-file")
                select new CaseFile { ... };

foreach (CaseFile cf in caseFiles)
{
    DoTheWork(cf);
}

このようにして、常に1つのCaseFileオブジェクトのみが作成されます。

于 2012-12-10T20:26:04.627 に答える
0

ToList を削除し、変数を IEnumerable として宣言する (または単に var を使用する) だけでうまくいくはずです。linq to XML の使用は、メモリ内のすべてのファイルをロードするため、大きなファイルには適用されない場合があります。代わりに XmlReader の使用を検討する必要があります

于 2012-12-10T20:15:49.133 に答える