I usually store for later reading blog posts. I was reading this post from my friend Vicente about Code Katas when I noticed that he used File.WriteAllLines to save a string[] and I thought "won't be faster to use StringBuilder + File.WriteAllText?". So I built a small test to check which one is faster.
Both code fragments create the first 20,000,000 integer numbers starting from zero, adding \n\r in the case of the StringBuilder to simulate different lines. The number is chosen by hand after having fun getting out of memory exceptions trying with Int32.MaxValue, and with 20M numbers I already achieved more than 1 second write operations in my SSD hard disk (both tests create a nice 180MB txt file).
string[] + WriteAllLines
- const int SIZE = 20000000;
- static void Main(string[] args)
- {
- Stopwatch stopWatchProgram = new Stopwatch();
- Stopwatch stopWatchWrite = new Stopwatch();
- stopWatchProgram.Start();
- string[] lines = new string[SIZE];
- int i = 0;
- for (i = 0; i < SIZE; i++)
- {
- lines[i] = i.ToString();
- }
- stopWatchWrite.Start();
- File.WriteAllLines(@"c:\testwritealllines.txt", lines);
- stopWatchWrite.Stop();
- stopWatchProgram.Stop();
- TimeSpan ts = stopWatchProgram.Elapsed;
- string elapsedTime = String.Format("Program: {0}:{1:00}", ts.Seconds, ts.Milliseconds);
- Console.WriteLine(elapsedTime);
- ts = stopWatchWrite.Elapsed;
- elapsedTime = String.Format("Write file: {0}:{1:00}", ts.Seconds, ts.Milliseconds);
- Console.WriteLine(elapsedTime);
- Console.ReadLine();
- }
StringBuilder + WriteAllText
- const int SIZE = 20000000;
- static void Main(string[] args)
- {
- Stopwatch stopWatchProgram = new Stopwatch();
- Stopwatch stopWatchWrite = new Stopwatch();
- stopWatchProgram.Start();
- StringBuilder lines = new StringBuilder(SIZE);
- int i = 0;
- for (i = 0; i < SIZE; i++)
- {
- lines.Append(i.ToString());
- lines.Append("\n\r");
- }
- stopWatchWrite.Start();
- File.WriteAllText(@"c:\testwritealltext.txt", lines.ToString());
- stopWatchWrite.Stop();
- stopWatchProgram.Stop();
- TimeSpan ts = stopWatchProgram.Elapsed;
- string elapsedTime = String.Format("Program: {0}:{1:00}", ts.Seconds, ts.Milliseconds);
- Console.WriteLine(elapsedTime);
- ts = stopWatchWrite.Elapsed;
- elapsedTime = String.Format("Write file: {0}:{1:00}", ts.Seconds, ts.Milliseconds);
- Console.WriteLine(elapsedTime);
- Console.ReadLine();
- }
And the results are:
string[] + WriteAllLines:
Program: 9.468
Write file: 2.607
StringBuilder + WriteAllText:
Program: 5.791
Write file: 1.138
Using Stringbuilder seems to be faster overall: 3.6 less seconds calculating the "lines" and less than half time writing the file.
While taking the units into account it doesn't matter which one to use (1 second or 2 is not much for us human beings) it is interesting that even with a non-properly sized Stringbuilder it performs faster (a proper starting capacity means no need to redimensionate it internally to increase the capacity when gets full).
I didn't do any advanced tests like writing in buffers with the size of my HDD cluster blocks, maybe doing a buffered Stringbuilder contents read and FileStream write in blocks of for example 4KB would be faster, but would add a complexity that is too much for a simple text write into a file.
Anyway, as usual StringBuilder proves to be a worthy candiate for string operations, and this posts proves that I should sleep more and code less stupid tests :)
Tags: Development