StringReader. In C# there are many ways to separate a string into lines. With StringReader, we read lines from a string individually in the order they appear.
The StringReader type enables us to access string data through a stream-oriented interface. It can replace Split() method calls, and sometimes improve performance.
Example. StringReader is a class found in the System.IO namespace. The instance constructor receives a string parameter. This is stored internally as a field in the StringReader.
Start We use a const string from the metadata to instantiate the StringReader instance.
Next We can then read each line individually from the string data, in a way similar to reading a file with StreamReader.
using System;
using System.IO;
class Program
{
const string _input = "Dot Net Perls\nA B\nC D";
static void Main()
{
// Creates new StringReader instance from System.IO
using (StringReader reader = new StringReader(_input))
{
// Loop over the lines in the string.
int count = 0;
string line;
while ((line = reader.ReadLine()) != null)
{
count++;
Console.WriteLine("Line {0}: {1}", count, line);
}
}
}
}Line 1: Dot Net Perls
Line 2: A B
Line 3: C D
Benchmark. How efficient is StringReader in comparison to the Split method? We ran a simple benchmark that separates into lines a string literal with several newline characters in it.
Version 1 This version of the method counts the number of non-newline characters in the lines using a StringReader.
Version 2 This version uses the Split method, along with a Length property access on the resulting array, to count lines.
Result As of 2024, it is faster to use Split than StringReader. Older versions of .NET may have other results.
using System;
using System.Diagnostics;
using System.IO;
class Program
{
static int Method1(string data)
{
int count = 0;
using (StringReader reader = new StringReader(data))
{
while (true)
{
string line = reader.ReadLine();
if (line == null)
{
break;
}
count += line.Length;
}
}
return count;
}
static int Method2(string data)
{
int count = 0;
string[] lines = data.Split(new char[] { '\n' });
foreach (string line in lines)
{
count += line.Length;
}
return count;
}
static void Main()
{
const string data = "Dot\nNet\nPerls\nA B C\nD E F";
Console.WriteLine(Method1(data));
Console.WriteLine(Method2(data));
const int max = 1000000;
// Version 1: use StringReader.
var s1 = Stopwatch.StartNew();
for (int i = 0; i < max; i++)
{
Method1(data);
}
s1.Stop();
// Version 2: use Split.
var s2 = Stopwatch.StartNew();
for (int i = 0; i < max; i++)
{
Method2(data);
}
s2.Stop();
Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000000) / max).ToString("0.00 ns"));
Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000000) / max).ToString("0.00 ns"));
}
}21
21
161.42 ns StringReader
67.73 ns Split
Read blocks. Read() can be used to populate a character array (a block) based on a range of the StringReader buffer. The buffer must be allocated before you call the method.
Internals. StringReader is a class with a member field string, an integer position, and an integer length. All the logic on the StringReader is based on the values of these three fields.
ReadLine internals. The ReadLine method on StringReader simply scans for the next newline starting at the current position, and then returns a substring based on the field string.
Tip StringReader internally stores only one string. It allocates and copies new strings each time you call Read methods.
Summary. StringReader provides methods that are stream-oriented, enabling you to use a string as a file stream. StringReader is useful for looping over the lines in a string.
Dot Net Perls is a collection of tested code examples. Pages are continually updated to stay current, with code correctness a top priority.
Sam Allen is passionate about computer languages. In the past, his work has been recommended by Apple and Microsoft and he has studied computers at a selective university in the United States.
This page was last updated on Dec 9, 2024 (benchmark).