Writing to the result file (and, more importantly, loading it every time you want to add an item) really kills you. Saving all the data that you want to write to memory is also problematic, if not for any other reason, then you may not have enough memory to do this. You need medium soil, and that means you want to dose. Read in a few hundred elements, store them in a structure in memory, and then when it gets big enough (play with the batch size to see what works best), write them all to the output file (s).
Therefore, we will start with this Batch function, which unloads IEnumerable :
public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> source, int batchSize) { List<T> buffer = new List<T>(batchSize); foreach (T item in source) { buffer.Add(item); if (buffer.Count >= batchSize) { yield return buffer; buffer = new List<T>(batchSize); } } if (buffer.Count >= 0) { yield return buffer; } }
Then, the query you use can actually be reorganized to use LINQ more efficiently. You have several options that actually do nothing and can use SelectMany instead of explicit foreach loops to pull it all into a single request.
var batchesToWrite = sourceList.SelectMany(file => XDocument.Load(file).Descendants("PCBDatabase").Elements()) .Select((element, index) => new { element, index, file = Path.Combine(xmlDestDir, element.Elements().First().Name + "Uber.xml"), }) .Batch(batchsize) .Select(batch => batch.GroupBy(element => element.file));
Then simply write out each of the batches:
foreach (var batch in batchesToWrite) { foreach (var group in batch) { WriteElementsToFile(group.Select(element => element.element), group.Key); } }
Regarding the actual writing of the elements in the file, I extracted this from the method, because there are probably different ways of writing your output. You can start with the implementation you are using, just to find out how you do it:
private static void WriteElementsToFile(IEnumerable<XElement> elements, string path) { XElement xeDoc = XElement.Load(path); foreach (var element in elements) xeDoc.Add(element); xeDoc.Save(path); }
But you still have a problem that you read in the entire input file to add items to the end. Only one of them can reduce this enough for your purposes, but if it is not, you can use this method yourself, perhaps using something other than LINQ to XML to write the results so that you donβt have to download everything file in memory to create this document.