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.
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
.
const
string
from the metadata to instantiate the StringReader
instance.string
data, in a way similar to reading a file with StreamReader
.while
-loop uses an embedded assignment and checks the string
variable result for null
to detect the end of file condition.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
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.
StringReader
.Split
method, along with a Length
property access on the resulting array, to count lines.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()
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.
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
internalsThe 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
.
StringReader
internally stores only one string
. It allocates and copies new strings each time you call Read methods.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
.