Замечания, уже сделанные в отношении BaseStream, действительны и важны. Однако бывают ситуации, когда вы хотите прочитать текст и знать, где в тексте вы находитесь. Все еще может быть полезно записать это как класс, чтобы упростить повторное использование.
Я попытался написать такой класс сейчас. Вроде работает правильно, но довольно медленно. Это должно быть хорошо, когда производительность не имеет решающего значения (она не настолько медленная, см. ниже).
Я использую ту же логику для отслеживания положения в тексте независимо от того, читаете ли вы символ за раз, один буфер за раз или одну строку за раз. Хотя я уверен, что это можно сделать лучше, отказавшись от этого, это значительно упростило реализацию... и, я надеюсь, следование коду.
Я сделал очень простое сравнение производительности метода ReadLine (который, как мне кажется, является самым слабым местом этой реализации) с StreamReader, и разница составляет почти порядок. Я получил 22 МБ/с, используя класс StreamReaderEx, но почти в 9 раз больше, используя StreamReader напрямую (на моем ноутбуке с SSD). Хотя это может быть интересно, я не знаю, как правильно провести тест на чтение; возможно, используя 2 одинаковых файла, каждый из которых больше, чем дисковый буфер, и читая их поочередно ..? По крайней мере, мой простой тест дает стабильные результаты, когда я запускаю его несколько раз и независимо от того, какой класс сначала читает тестовый файл.
Символ NewLine по умолчанию имеет значение Environment.NewLine, но может быть установлен на любую строку длиной 1 или 2. Читатель рассматривает только этот символ как новую строку, что может быть недостатком. По крайней мере, я знаю, что Visual Studio довольно много раз подсказывала мне, что файл, который я открываю, «имеет несогласованные новые строки».
Обратите внимание, что я не включил класс Guard; это простой служебный класс, и из контекста должно быть понятно, как его заменить. Вы даже можете удалить его, но вы потеряете проверку некоторых аргументов, и, таким образом, полученный код будет более далеким от «правильного». Например, Guard.NotNull(s, "s") просто проверяет, что s не равно null, вызывая ArgumentNullException (с именем аргумента "s", следовательно, второй параметр), если это так.
Хватит болтать, вот код:
public class StreamReaderEx : StreamReader
{
// NewLine characters (magic value -1: "not used").
int newLine1, newLine2;
// The last character read was the first character of the NewLine symbol AND we are using a two-character symbol.
bool insideNewLine;
// StringBuilder used for ReadLine implementation.
StringBuilder lineBuilder = new StringBuilder();
public StreamReaderEx(string path, string newLine = "\r\n") : base(path)
{
init(newLine);
}
public StreamReaderEx(Stream s, string newLine = "\r\n") : base(s)
{
init(newLine);
}
public string NewLine
{
get { return "" + (char)newLine1 + (char)newLine2; }
private set
{
Guard.NotNull(value, "value");
Guard.Range(value.Length, 1, 2, "Only 1 to 2 character NewLine symbols are supported.");
newLine1 = value[0];
newLine2 = (value.Length == 2 ? value[1] : -1);
}
}
public int LineNumber { get; private set; }
public int LinePosition { get; private set; }
public override int Read()
{
int next = base.Read();
trackTextPosition(next);
return next;
}
public override int Read(char[] buffer, int index, int count)
{
int n = base.Read(buffer, index, count);
for (int i = 0; i
person
The Dag
schedule
23.01.2012