Derek Patton
Derek Patton

Reputation: 233

Is is better to Stream.Write multiple times or concatenate string and Stream.Write once?

I was just wondering, in terms of performance, which one is better (I'm using a StreamWriter in a FileStream):

  1. Calling Stream.Write() multiple times:

StreamWriter sw = new StreamWriter(fs);
for (int i = 0; i < 100; i++)
{
    sw.Write(myList[i].ToString());
}

  1. Concatenate all my strings into a single string and then calling Steam.Write() once:

StreamWriter sw = new StreamWriter(fs);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 100; i++)
{
    sb.Append(myList[i].ToString());
}
sw.Write(sb.ToString());

Thanks!

Upvotes: 3

Views: 2941

Answers (3)

Kim Homann
Kim Homann

Reputation: 3229

I measured the duration using 3 different approaches:

class Program
{
    private static readonly int NumLines = 100000;
    private static readonly int NumWords = 200;
    private static readonly string Word = "Oberbuergermeister";

    static void Main(string[] args)
    {
        var stopWatch = new Stopwatch();

        // approach 1: use string builder to cache all, then write
        stopWatch.Start();
        Approach1();
        stopWatch.Stop();
        Console.WriteLine(stopWatch.Elapsed.ToString());
        stopWatch.Reset();

        // approach 2: write stuff line by line
        stopWatch.Start();
        Approach2();
        stopWatch.Stop();
        Console.WriteLine(stopWatch.Elapsed.ToString());
        stopWatch.Reset();

        // approach 3: write stuff string by string
        stopWatch.Start();
        Approach3();
        stopWatch.Stop();
        Console.WriteLine(stopWatch.Elapsed.ToString());
    }

    private static void Approach1()
    {
        var writer = new System.IO.StreamWriter("C:\\temp\\1");

        var builder = new StringBuilder();
        for (int cnt1 = 0; cnt1 < NumLines; cnt1++)
        {
            for (int cnt2 = 0; cnt2 < NumWords; cnt2++)
            {
                builder.Append(Word);
                builder.Append(";");
            }
            builder.AppendLine();
        }

        writer.WriteLine(builder.ToString());

        writer.Close();
    }

    private static void Approach2()
    {
        var writer = new System.IO.StreamWriter("C:\\temp\\2");

        var builder = new StringBuilder();
        for (int cnt1 = 0; cnt1 < NumLines; cnt1++)
        {
            for (int cnt2 = 0; cnt2 < NumWords; cnt2++)
            {
                builder.Append(Word);
                builder.Append(";");
            }
            writer.WriteLine(builder.ToString());
            builder.Clear();
        }

        writer.Close();
    }

    private static void Approach3()
    {
        var writer = new System.IO.StreamWriter("C:\\temp\\3");

        for (int cnt1 = 0; cnt1 < NumLines; cnt1++)
        {
            for (int cnt2 = 0; cnt2 < NumWords; cnt2++)
            {
                writer.Write(Word);
                writer.Write(";");
            }
            writer.WriteLine();
        }

        writer.Close();
    }
}

Here's the output:

00:00:02.8457431
00:00:01.5492287
00:00:01.4843888

Looks like it's best to call StreamWriter.Write() as often as possible and completely leave the caching to .NET. I haven't tried char by char, but line by line seems to be good enough anyway.

Upvotes: 1

Josh Part
Josh Part

Reputation: 2164

In my personal experience, there's something else you should take on consideration before chosing one or another: if you write to the stream line by line, every line of the complete text is a chance for an I/O exception (specially when writing to disk); thus the more lines you're going to write, the more error-prone your code is. So, if there's no significant difference between your two approaches, either consider the second one, or have your code ready to recover if an exception ocurrs when writing half of the complete text.

Upvotes: 1

C.Evenhuis
C.Evenhuis

Reputation: 26436

There is no single answer to this. You can imagine that writing byte by byte, or character by character, usually causes overhead because each chunk of data travels through the layers of abstraction.

However you can also imagine that buffering as much as possible may not be optimal, ie. if you send data over a network stream, you would like the network to start transmitting data as soon as possible. And your application is busy buffering, so perhaps you're just moving the delay around instead of fixing anything.

In the case of a FileStream the operating system takes care of buffering, in normal circumstances you probably won't notice any difference between your two approaches.

Just write the data as is most fitting for your application, and if you find this is a bottleneck to your application, implement a buffered stream layer between the StreamWriter and the underlying Stream to counter the problem.

Upvotes: 3

Related Questions