Как добавить большие XML-файлы в C#, эффективно используя память

Есть ли способ объединить два XmlDocument, не удерживая первый в памяти?

Мне приходится перебирать список до сотни больших (~ 300 МБ) файлов XML, добавляя к каждому до 1000 узлов, повторяя весь процесс несколько раз (поскольку новый список узлов очищается для экономии памяти). В настоящее время я загружаю весь XmlDocument в память перед добавлением новых узлов, что в настоящее время невозможно.

Что бы вы сказали, это лучший способ сделать это? У меня есть несколько идей, но я не уверен, что лучше:

  1. Никогда не загружайте весь XMLDocument, вместо этого используйте одновременно XmlReader и XmlWriter для записи во временный файл, который впоследствии переименовывается.
  2. Создайте XmlDocument только для новых узлов, а затем вручную запишите его в существующий файл (т.е. file.WriteLine( "<node>\n" )
  3. Что-то другое?

Любая помощь будет высоко ценится.

Изменить Еще немного подробностей в ответ на некоторые комментарии:

Программа анализирует несколько больших журналов в формате XML, группируя их в разные файлы по источнику. Его нужно запускать только один раз в день, и после того, как XML написан, есть легкая проприетарная программа чтения, которая дает отчеты о данных. Программе нужно запускаться только один раз в день, поэтому она может быть медленной, но работает на сервере, который выполняет другие действия, в основном сжатие и передачу файлов, на которые нельзя слишком сильно повлиять.

База данных, вероятно, была бы проще, но компания не собирается делать это в ближайшее время!

Как есть, программа работает на машине разработчика, используя максимум несколько ГБ памяти, но выдает исключения из памяти при запуске на сервере.

Окончательное редактирование Задача имеет довольно низкий приоритет, поэтому получение базы данных потребует дополнительных затрат (хотя я рассмотрю монго).

Файл будет только добавлен и не будет расти бесконечно — каждый окончательный файл предназначен только для дневного журнала, а на следующий день создаются новые файлы.

Я, вероятно, буду использовать метод XmlReader/Writer, так как проще всего обеспечить достоверность XML, но я принял во внимание все ваши комментарии/ответы. Я знаю, что такие большие XML-файлы — не очень хорошее решение, но это то, чем я ограничен, поэтому спасибо за всю оказанную помощь.


person Overlord_Dave    schedule 03.08.2012    source источник
comment
Я думаю, что номер 1 - это путь, но у меня нет практического опыта работы с такими большими файлами.   -  person Jeff Mercado    schedule 03.08.2012
comment
Какова конечная цель, я имею в виду ее достижение   -  person HatSoft    schedule 03.08.2012
comment
Можете ли вы дать более подробную информацию о проблеме? Возможно, переход на базу данных — лучшее решение.   -  person eabraham    schedule 03.08.2012
comment
Я ответил на некоторые комментарии и отредактировал. @JeffMercado Это будет работать, но потенциально может быть слишком тяжелым для процессора.   -  person Overlord_Dave    schedule 03.08.2012
comment
Я предлагаю выполнять большинство манипуляций с файлами с временными файлами и, если они увенчаются успехом, сделать File.Replace старого файла с временным файлом. Это сохраняет ваши данные, если во время манипуляций что-то пойдет не так.   -  person Dour High Arch    schedule 03.08.2012
comment
Если это такой большой набор данных (и при условии, что вы не можете использовать базу данных), то не лучше ли использовать двоичный файл? Нет необходимости считывать все эти данные в память в виде текста; выгрузите его в XML, когда закончите с обновлениями. А еще лучше, почему бы не использовать Mongo DB (установка не требуется, просто скачайте бинарники, хорошо интегрируется с C#)? Просто безумие работать с текстовым представлением таких больших наборов данных.   -  person McGarnagle    schedule 03.08.2012
comment
означает ли второй вариант, что новые узлы, добавленные в xml, всегда добавляются в смысле добавления файла? если да, то 2-й - лучший путь. в противном случае 1-й лучше.   -  person Ankush    schedule 03.08.2012
comment
В ответ на вопрос Что бы вы сказали, это лучший способ сделать это? Я думаю, что ответ — использовать базу данных размером 300 МБ; не XML-файл размером 300 МБ. Это наверняка сильно облегчит задачу.   -  person Dan    schedule 03.08.2012
comment
Вы на самом деле обрабатываете каждый XML-файл или вам просто нужно добавить в конец фиксированный набор узлов, которые не зависят от содержимого XML-документа?   -  person lsoliveira    schedule 03.08.2012
comment
Вы действительно просто добавляете? Если это так, файлы будут расти бесконечно, что важно иметь в виду. Кроме того, если вы всегда добавляете в конец, то использование метода, требующего чтения всего файла (например, XmlReader), со временем будет становиться все медленнее. Лучше всего объединить #1 и #2, создав XML-фрагмент, а затем используя файловые операции, чтобы вставить его в существующий файл.   -  person Brian Reischl    schedule 03.08.2012
comment
Во сколько вашей компании обходится решение этой проблемы по сравнению с добавлением дополнительной памяти на сервер?   -  person Chuck Savage    schedule 04.08.2012


Ответы (1)


Если вы хотите быть полностью уверены в структуре XML, лучше всего использовать XMLWriter и XMLReader.

Однако для максимально возможной производительности вы можете быстро воссоздать этот код, используя прямые строковые функции. Вы можете сделать это, хотя вы потеряете возможность проверить структуру XML — если в одном файле будет ошибка, вы не сможете ее исправить:

using (StreamWriter sw = new StreamWriter("out.xml")) {
    foreach (string filename in files) {
        sw.Write(String.Format(@"<inputfile name=""{0}"">", filename));
        using (StreamReader sr = new StreamReader(filename)) {
            // Using .NET 4's CopyTo(); alternatively try http://bit.ly/RiovFX
            if (max_performance) {
                sr.CopyTo(sw);
            } else {
                string line = sr.ReadLine();
                // parse the line and make any modifications you want
                sw.Write(line);
                sw.Write("\n");
            }
        }
        sw.Write("</inputfile>");
    }
}

В зависимости от того, как структурированы ваши входные файлы XML, вы можете удалить заголовки XML, возможно, элемент документа или несколько других ненужных структур. Вы можете сделать это, разбирая файл построчно

person Ted Spence    schedule 03.08.2012
comment
спасибо за ссылку на CopyStream - даже если я не использую ее сейчас, я уверен, что она будет полезна в будущем! - person Overlord_Dave; 06.08.2012
comment
Глупый я - я забыл о методе .NET 4 CopyTo - объяснение здесь msdn.microsoft .com/en-us/library/dd782932.aspx. Теперь он встроен. - person Ted Spence; 09.08.2012