Удалить последние x строк из потокового ридера - PullRequest
3 голосов
/ 09 марта 2012

Мне нужно прочитать все, кроме последних x строк из файла в потоковом считывателе в C #.Каков наилучший способ сделать это?

Большое спасибо!

Ответы [ 3 ]

3 голосов
/ 09 марта 2012

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

string[] lines = File.ReadAllLines(@"C:\test.txt");

Или если вам действительно нужно работать с StreamReaders:

using (StreamReader reader = new StreamReader(@"C:\test.txt"))
        {
            while (!reader.EndOfStream)
            {
                Console.WriteLine(reader.ReadLine());
            }
        }
3 голосов
/ 09 марта 2012

Если это большой файл, можно ли просто перейти к концу файла и проверить байты в обратном порядке на наличие символа '\ n'?Я знаю, что \ n и \ r \ n существует.Я набрал следующий код и протестировал довольно простой файл.Можете ли вы попробовать проверить это на файлах, которые у вас есть?Я знаю, что мое решение выглядит долго, но я думаю, вы обнаружите, что это быстрее, чем читать с самого начала и переписывать весь файл.

public static void Truncate(string file, int lines)
{
    using (FileStream fs = File.Open(file, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None))
    {
        fs.Position = fs.Length;

        // \n \r\n (both uses \n for lines)
        const int BUFFER_SIZE = 2048;

        // Start at the end until # lines have been encountered, record the position, then truncate the file
        long currentPosition = fs.Position;
        int linesProcessed = 0;

        byte[] buffer = new byte[BUFFER_SIZE];
        while (linesProcessed < linesToTruncate && currentPosition > 0)
        {
            int bytesRead = FillBuffer(buffer, fs);

            // We now have a buffer containing the later contents of the file
            for (int i = bytesRead - 1; i >= 0; i--)
            {
                 currentPosition--;
                 if (buffer[i] == '\n')
                 {
                     linesProcessed++;
                     if (linesProcessed == linesToTruncate)
                         break;
                 }
            }
        }

        // Truncate the file
        fs.SetLength(currentPosition);
    }
}

private static int FillBuffer(byte[] buffer, FileStream fs)
{
    if (fs.Position == 0)
        return 0;

    int bytesRead = 0;
    int currentByteOffset = 0;

    // Calculate how many bytes of the buffer can be filled (remember that we're going in reverse)
    long expectedBytesToRead = (fs.Position < buffer.Length) ? fs.Position : buffer.Length;
    fs.Position -= expectedBytesToRead;

    while (bytesRead < expectedBytesToRead)
    {
        bytesRead += fs.Read(buffer, currentByteOffset, buffer.Length - bytesRead);
        currentByteOffset += bytesRead;
    }

    // We have to reset the position again because we moved the reader forward;
    fs.Position -= bytesRead;
    return bytesRead;
}

Поскольку вы планируете только удалить конец файла, кажется, что переписывать все будет расточительно, особенно, если это большой файл и маленький N. Конечно, можно привести аргумент, что если кто-тохотел исключить все строки, тогда более эффективен переход от начала к концу.

3 голосов
/ 09 марта 2012

Вы действительно не читаете INTO StreamReader.Фактически, для запрашиваемого вами шаблона вам вообще не нужен StreamReader.System.IO.File имеет полезный статический метод 'ReadLines', который вы можете использовать вместо:

IEnumerable<string> allBut = File.ReadLines(path).Reverse().Skip(5).Reverse();

Предыдущая некорректная версия, обратно в ответ на ветку комментариев

List<string> allLines = File.ReadLines(path).ToList();
IEnumerable<string> allBut = allLines.Take(allLines.Count - 5);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...