#c_sharp #xml
Есть файл xml-файл вида:под тегами скрыто: имя файла, исходный путь к файлу и путь, по которому данный файл требуется скопировать. Решил парсить файл в список структур: 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 записей? Подходит ли данный способ чтения файла под эту задачу? test.log C:/ C:/copy/ Win8.iso C:/ C:/copy/ ... ... ... TemplateNew.xlsx C:/ C:/copy/
Ответы
Ответ 1
Нужно использовать потоковый 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 } } Ответ 2
Вариант с ленивым чтением, xml не будет загружаться в память полностью, как в вашем случае, т.е. можно сделать поточную обработку, можно читать и пачками, если написать Extension, который читает IEnumerable<> и разбивает его на порции заданного размера IEnumerable> public class FileModel { public string Name { get; set;} public string SourcePath { get; set; } public string TargetPath { get; set; } } public static IEnumerableReadXml(string path) { using (var fileStream = File.OpenRead(path)) using (var streamReader = new StreamReader(fileStream, Encoding.UTF8)) using (var reader = XmlReader.Create(streamReader)) { while (reader.Read()) { if (reader.NodeType != XmlNodeType.Element || reader.Name != "file") { continue; } XElement el = XElement.ReadFrom(reader) as XElement; var fileModel = new FileModel { Name = (string)el.Element("name"), SourcePath = (string)el.Element("sourcePath"), TargetPath = (string)el.Element("targetPath"), }; yield return fileModel; } } }
Комментариев нет:
Отправить комментарий