C # Как пропустить количество строк при чтении текстового файла с помощью Stream Reader? - PullRequest
18 голосов
/ 11 декабря 2010

У меня есть программа, которая читает текстовый файл и обрабатывает его для разделения на разделы.

Таким образом, вопрос в том, как изменить программу, чтобы позволить программе пропустить чтение первых 5 строкфайл при использовании Stream Reader для чтения файла?

Может кто-нибудь посоветует, пожалуйста, коды?Спасибо!

Коды:

class Program
{
    static void Main(string[] args)
    {
        TextReader tr = new StreamReader(@"C:\Test\new.txt");

        String SplitBy = "----------------------------------------";

        // Skip first 5 lines of the text file?
        String fullLog = tr.ReadToEnd();

        String[] sections = fullLog.Split(new string[] { SplitBy }, StringSplitOptions.None);

        //String[] lines = sections.Skip(5).ToArray();

        foreach (String r in sections)
        {
            Console.WriteLine(r);
            Console.WriteLine("============================================================");
        }
    }
}

Ответы [ 6 ]

25 голосов
/ 11 декабря 2010

Попробуйте следующее

// Skip 5 lines
for(var i = 0; i < 5; i++) {
  tr.ReadLine();
}

// Read the rest
string remainingText = tr.ReadToEnd();
11 голосов
/ 11 декабря 2010

Если строки зафиксированы, то наиболее эффективный способ выглядит следующим образом:

using( Stream stream = File.Open(fileName, FileMode.Open) )
{
    stream.Seek(bytesPerLine * (myLine - 1), SeekOrigin.Begin);
    using( StreamReader reader = new StreamReader(stream) )
    {
        string line = reader.ReadLine();
    }
}

А если строки различаются по длине, вам придется просто читать их по очереди, как показано ниже.:

using (var sr = new StreamReader("file"))
{
    for (int i = 1; i <= 5; ++i)
        sr.ReadLine();
}
8 голосов
/ 31 января 2013

Если вы хотите использовать его несколько раз в своей программе, то, возможно, будет хорошей идеей создать собственный класс, унаследованный от StreamReader, с возможностью пропуска строк.

Нечто подобное может сделать:

class SkippableStreamReader : StreamReader
{
    public SkippableStreamReader(string path) : base(path) { }

    public void SkipLines(int linecount)
    {
        for (int i = 0; i < linecount; i++)
        {
            this.ReadLine();
        }
    }
}

после этого вы можете использовать функцию SkippableStreamReader для пропуска строк. Пример:

SkippableStreamReader exampleReader = new SkippableStreamReader("file_to_read");

//do stuff
//and when needed
exampleReader.SkipLines(number_of_lines_to_skip);
5 голосов
/ 16 сентября 2014

Я добавлю еще два предложения в список.

Если файл всегда будет, а вы будете только читать, я предлагаю:

var lines = File.ReadLines(@"C:\Test\new.txt").Skip(5).ToArray();

Файл.ReadLines не блокирует файл от других и загружает в память только необходимые строки.

Если ваш поток может поступать из других источников, то я предлагаю такой подход:

class Program
{
    static void Main(string[] args)
    {
        //it's up to you to get your stream
        var stream = GetStream();

        //Here is where you'll read your lines. 
        //Any Linq statement can be used here.
        var lines = ReadLines(stream).Skip(5).ToArray();

        //Go on and do whatever you want to do with your lines...
    }
}

public IEnumerable<string> ReadLines(Stream stream)
{
    using (var reader = new StreamReader(stream))
    {
        while (!reader.EndOfStream)
        {
            yield return reader.ReadLine();
        }
    }
}

Блок Iterator будетавтоматически очищать себя, как только вы закончите с этим. Здесь - статья Джона Скита, в которой подробно рассказывается, как это работает (прокрутите вниз до раздела «И наконец ...»).

1 голос
/ 11 декабря 2010

Полагаю, это так просто:

    static void Main(string[] args)
    {
        var tr = new StreamReader(@"C:\new.txt");

        var SplitBy = "----------------------------------------";

        // Skip first 5 lines of the text file?
        foreach (var i in Enumerable.Range(1, 5)) tr.ReadLine();
        var fullLog = tr.ReadToEnd(); 

        String[] sections = fullLog.Split(new string[] { SplitBy }, StringSplitOptions.None);

        //String[] lines = sections.Skip(5).ToArray();

        foreach (String r in sections)
        {
            Console.WriteLine(r);
            Console.WriteLine("============================================================");
        }
    }
0 голосов
/ 21 марта 2019

StreamReader с ReadLine или ReadToEnd фактически пойдет и прочитает байты в память, даже если вы не обрабатываете эти строки, они будут загружены, что повлияет на производительность приложения в случае большихфайлы (10+ МБ).

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

  1. Если вы знаетедлину линии вы можете рассчитать позицию и переместиться туда с помощью Stream.Seek.Это самый эффективный способ пропустить потоковое содержимое, не читая его.Проблема в том, что вы редко можете узнать длину строки.
var linesToSkip = 10;
using(var reader = new StreamReader(fileName) )
{
    reader.BaseStream.Seek(lineLength * (linesToSkip - 1), SeekOrigin.Begin);
    var myNextLine = reader.ReadLine();
    // TODO: process the line
}
Если вы не знаете длину строки, вы должны читать строку за строкой и пропускать их, пока не доберетесь до нужного номера строки.Проблема здесь в том, что номер строки высокий, вы получите удар по производительности
var linesToSkip = 10;
using (var reader = new StreamReader(fileName))
{
    for (int i = 1; i <= linesToSkip; ++i)
        reader.ReadLine();

    var myNextLine = reader.ReadLine();
    // TODO: process the line
}

И если вам нужно просто пропустить все, вы должны сделать это, не считывая весь контент в память:

using(var reader = new StreamReader(fileName) )
{
   reader.BaseStream.Seek(0, SeekOrigin.End);

   // You can wait here for other processes to write into this file and then the ReadLine will provide you with that content

   var myNextLine = reader.ReadLine();
   // TODO: process the line
}
...