Страницы

Поиск по вопросам

пятница, 5 апреля 2019 г.

Порционное чтение большого Xml файла с известной структурой

Есть файл xml-файл вида:
test.log C:/ C:/copy/ Win8.iso C:/ C:/copy/ TemplateNew.xlsx C:/ C:/copy/ ... ... ...
под тегами скрыто: имя файла, исходный путь к файлу и путь, по которому данный файл требуется скопировать.
Решил парсить файл в список структур:
var document = new XmlDocument(); document.Load(configPath);
XmlNode root = document.DocumentElement;
string name = ""; string source = ""; string target = ""; int iCount = 0;
foreach (XmlNode nodes in root.ChildNodes) { foreach (XmlNode tagname in nodes.ChildNodes) { if (tagname.Name == "name") { name = tagname.InnerText; } if (tagname.Name == "sourcePath") { source = tagname.InnerText; } if (tagname.Name == "targetPath") { target = tagname.InnerText; } } collect.Added(name, source, target); iCount++; }
Console.WriteLine("заполнено {0} элементов", iCount);
Но вот загвоздка, если предположить что файл будет размером, близким к бесконечности, то список превысит допустимые размеры оперативной памяти и я словлю исключение о её чрезмерном размере. Каким образом можно организовать порционное чтение данных, скажем, по 100 записей? Подходит ли данный способ чтения файла под эту задачу?


Ответ

Нужно использовать потоковый XmlReader. Загружать сразу все данные в коллекцию нельзя, т. к. по условию файл потенциально очень большой. Будем читать по 100 записей.
Создадим класс для данных:
class File { public string Name { get; set; } public string SourcePath { get; set; } public string TargetPath { get; set; } }
Метод, возвращающий список с указанным количеством записей (или меньше в самом конце):
IEnumerable> ReadFiles() { using (var reader = XmlReader.Create(fileName)) { var files = new List();
while (reader.ReadToFollowing("name")) { var file = new File(); file.Name = reader.ReadElementContentAsString();
reader.MoveToContent(); file.SourcePath = reader.ReadElementContentAsString();
reader.MoveToContent(); file.TargetPath = reader.ReadElementContentAsString();
files.Add(file);
if (files.Count % 100 == 0) { yield return files; files = new List(); } }
if (files.Count > 0) yield return files; } }
Использование этого метода:
foreach (var files in ReadFiles()) { // работаем с коллекцией files
foreach(var file in files) { // работаем с одним экземпляром file } }

Комментариев нет:

Отправить комментарий