Почему количество шагов FileStream.Position увеличивается в несколько раз?

У меня есть текстовый файл, который я хочу читать по строкам и записывать позицию в текстовом файле, когда я иду. После прочтения любой строки файла программа может выйти, и мне нужно возобновить чтение файла на следующей строке, когда он возобновится.

Вот пример кода:

using (FileStream fileStream = new FileStream("Sample.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
    fileStream.Seek(GetLastPositionInFile(), SeekOrigin.Begin);
    using (StreamReader streamReader = new StreamReader(fileStream))
    {
        while (!streamReader.EndOfStream)
        {
            string line = streamReader.ReadLine();
            DoSomethingInteresting(line);
            SaveLastPositionInFile(fileStream.Position);

            if (CheckSomeCondition())
            {
                break;
            }
        }
    }
}

Когда я запускаю этот код, значение fileStream.Position не изменяется после прочтения каждой строки, оно только продвигается после прочтения нескольких строк. Когда он изменяется, он увеличивается в кратных 1024. Теперь я предполагаю, что под обложками происходит некоторая буферизация, но как я могу записать точную позицию в файле?

Ответ 1

Это не FileStream, что отвечает - это StreamReader. Он читает 1K за раз для эффективности.

Отслеживание эффективного положения потока по отношению к StreamReader является сложным... особенно, поскольку ReadLine отбрасывает завершение строки, поэтому вы не можете точно восстановить исходные данные (это может закончились "\n" или "\ r\n" ). Было бы неплохо, если бы StreamReader разоблачил что-то, чтобы сделать это проще (я уверен, что он мог бы сделать это без особых трудностей), но я не думаю, что в текущем API вам ничего не поможет: (

Кстати, я бы предположил, что вместо использования EndOfStream вы продолжаете читать до тех пор, пока ReadLine не вернет null. Мне просто проще:

string line;
while ((line = reader.ReadLine()) != null)
{
    // Process the line
}

Ответ 2

Я согласен со Стефаном М., вероятно, это буферизация, которая приводит к неправильной позиции. Если это просто количество символов, которые вы прочитали, которые вы хотите отслеживать, чем я предлагаю вам сделать это самостоятельно, как в:

        using(FileStream fileStream = new FileStream("Sample.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
            fileStream.Seek(GetLastPositionInFile(), SeekOrigin.Begin);
            **Int32 position = 0;**
            using(StreamReader streamReader = new StreamReader(fileStream)) {
                while(!streamReader.EndOfStream) {
                    string line = streamReader.ReadLine();
                    **position += line.Length;**
                    DoSomethingInteresting(line);
                    **SaveLastPositionInFile(position);**

                    if(CheckSomeCondition()) {
                        break;
                    }
                }
            }
        }

Ответ 3

Предположите, что ваш файл не слишком большой, почему бы не прочитать все это в больших кусках, а затем манипулировать строкой - возможно, быстрее, чем остановка и перейти в/в.

Например,

            //load entire file
            StreamReader srFile = new StreamReader(strFileName);
            StringBuilder sbFileContents = new StringBuilder();
            char[] acBuffer = new char[32768];
            while (srFile.ReadBlock(acBuffer, 0, acBuffer.Length)
                > 0)
            {
                sbFileContents.Append(acBuffer);
                acBuffer = new char[32768];
            }

            srFile.Close();