How to read text file by particular line separator character?
I would implement something like George's answer, but as an extension method that avoids loading the whole file at once (not tested, but something like this):
static class ExtensionsForTextReader
{
public static IEnumerable<string> ReadLines (this TextReader reader, char delimiter)
{
List<char> chars = new List<char> ();
while (reader.Peek() >= 0)
{
char c = (char)reader.Read ();
if (c == delimiter) {
yield return new String(chars.ToArray());
chars.Clear ();
continue;
}
chars.Add(c);
}
}
}
Which could then be used like:
using (StreamReader sr = new StreamReader(FileName, Encoding.Default))
{
foreach (var line in sr.ReadLines ('\n'))
Console.WriteLine (line);
}
string text = sr.ReadToEnd();
string[] lines = text.Split('\r');
foreach(string s in lines)
{
// Consume
}
I loved the answer @Pete gave. I would just like to submit a slight modification. This will allow you to pass a string delimiter instead of just a single character:
using System;
using System.IO;
using System.Collections.Generic;
internal static class StreamReaderExtensions
{
public static IEnumerable<string> ReadUntil(this StreamReader reader, string delimiter)
{
List<char> buffer = new List<char>();
CircularBuffer<char> delim_buffer = new CircularBuffer<char>(delimiter.Length);
while (reader.Peek() >= 0)
{
char c = (char)reader.Read();
delim_buffer.Enqueue(c);
if (delim_buffer.ToString() == delimiter || reader.EndOfStream)
{
if (buffer.Count > 0)
{
if (!reader.EndOfStream)
{
yield return new String(buffer.ToArray()).Replace(delimiter.Substring(0, delimiter.Length - 1), string.Empty);
}
else
{
buffer.Add(c);
yield return new String(buffer.ToArray());
}
buffer.Clear();
}
continue;
}
buffer.Add(c);
}
}
private class CircularBuffer<T> : Queue<T>
{
private int _capacity;
public CircularBuffer(int capacity)
: base(capacity)
{
_capacity = capacity;
}
new public void Enqueue(T item)
{
if (base.Count == _capacity)
{
base.Dequeue();
}
base.Enqueue(item);
}
public override string ToString()
{
List<String> items = new List<string>();
foreach (var x in this)
{
items.Add(x.ToString());
};
return String.Join("", items);
}
}
}