How to efficiently write a large text file in C#?
Solution 1:
File I/O operations are generally well optimized in modern operating systems. You shouldn't try to assemble the entire string for the file in memory ... just write it out piece by piece. The FileStream
will take care of buffering and other performance considerations.
You can make this change easily by moving:
using (StreamWriter outfile = new StreamWriter(filePath)) {
to the top of the function, and getting rid of the StringBuilder
writing directly to the file instead.
There are several reasons why you should avoid building up large strings in memory:
- It can actually perform worse, because the
StringBuilder
has to increase its capacity as you write to it, resulting in reallocation and copying of memory. - It may require more memory than you can physically allocate - which may result in the use of virtual memory (the swap file) which is much slower than RAM.
- For truly large files (> 2Gb) you will run out of address space (on 32-bit platforms) and will fail to ever complete.
- To write the
StringBuilder
contents to a file you have to useToString()
which effectively doubles the memory consumption of the process since both copies must be in memory for a period of time. This operation may also fail if your address space is sufficiently fragmented, such that a single contiguous block of memory cannot be allocated.
Solution 2:
Just move the using
statement so it encompasses the whole of your code, and write directly to the file. I see no point in keeping it all in memory first.
Solution 3:
Write one string at a time using StreamWriter.Write rather than caching everything in a StringBuilder.
Solution 4:
This might be old but I had a file to write with about 17 million lines so I ended up batching the writes every 10k lines similar to these lines
for (i6 = 1; i6 <= ball; i6++)
{ //this is middle of 6 deep nest ..
counter++;
// modus to get a value at every so often 10k lines
divtrue = counter % 10000; // remainder operator % for 10k
// build the string of fields with \n at the end
lineout = lineout + whatever
// the magic 10k block here
if (divtrue.Equals(0))
{
using (StreamWriter outFile = new StreamWriter(@filepath, true))
{
// write the 10k lines with .write NOT writeline..
outFile.Write(lineout);
}
// reset the string so we dont do silly like memory overflow
lineout = "";
}
}
In my case it was MUCH faster then one line at a time.