2013-08-14 3 views
1

Я хочу прочитать .txt-файл в C#, но я не буду читать все строки одновременно. Например, рассмотрите 500 строк текстового файла. Я хочу, чтобы функция выполнялась 25 раз и каждый раз читала 20 последовательных строк. При первом вызове функции будут прочитаны строки от 1 до 20, а во второй раз это будет прочитано.C# Чтение потока

Ниже простой код делает это в C++, но я не знаю, как добиться этого в C#:

string readLines(ifstream& i) 
{ 
    string totalLine="", line = ""; 
    for(int i = 0; i < 20; i++){ 
      getline(i, line); 

      totalLine += line; 
    } 
    return totalLine; 
} 

int main() 
{ 

    // ... 
    ifstream in; 
    in.open(filename.c_str()); 
    while(true){ 
     string next20 = readLines(in); 
     // so something with 20 lines. 
    } 
    // ... 

} 
+4

[Как читать текст из файла:] (http://msdn.microsoft.com/en-us/library/db5x7c0d.aspx) –

+0

Код, указанный в C++, не работает в все - это просто петли, читающие * все * линии. Это легко сделать и на C# ... foreach (строка строки в File.ReadLines (...)) '. В C# не слишком плохое дозирование ... –

+0

Это просто быстрый пример. Что я имел в виду, так это то, что если вы вставляете оператор while в функцию и даже если вы преждевременно прекратите чтение файла, он будет продолжен там, где он был остановлен. –

ответ

3

Есть различные варианты здесь, но один простой подход был бы:

using (var reader = File.OpenText("file.txt")) 
{ 
    for (int i = 0; i < 25; i++) 
    { 
     HandleLines(reader); 
    } 
} 

... 

private void HandleLines(TextReader reader) 
{ 
    for (int i = 0; i < 20; i++) 
    { 
     string line = reader.ReadLine(); 
     if (line != null) // Handle the file ending early 
     { 
      // Process the line 
     } 
    } 
} 
0

К сожалению. GroupBy не оценивает лениво, так что это будет жадно потреблять весь файл

var twentyLineGroups = 
    File.ReadLines(somePath) 
     .Select((line, index) => new {line, index}) 
     .GroupBy(x => x.index/20) 
     .Select(g => g.Select(x => x.line)); 

foreach(IEnumerable<string> twentyLineGroup in twentyLineGroups) 
{ 
    foreach(string line in twentyLineGroup) 
    { 
     //tada! 
    } 
} 

+0

Таким образом, этот фрагмент кода фактически делит строки на 20, а затем перебирает строки по кругу над группами, не так ли? Я очень не знаком с функциями первого оператора. –

1

Вы могли бы написать метод Batch() следующим образом:

public static IEnumerable<string> Batch(IEnumerable<string> input, int batchSize) 
{ 
    int n = 0; 
    var block = new StringBuilder(); 

    foreach (var line in input) 
    { 
     block.AppendLine(line); 

     if (++n != batchSize) 
      continue; 

     yield return block.ToString(); 
     block.Clear(); 
     n = 0; 
    } 

    if (n != 0) 
     yield return block.ToString(); 
} 

И вызов это так:

string filename = "<Your filename goes here>"; 
var batches = Batch(File.ReadLines(filename), 20); 

foreach (var block in batches) 
{ 
    Console.Write(block); 
    Console.WriteLine("------------------------"); 
} 
2

Если пытаются вызвать LineRead() в наименее раз число можно и вы хотите минимальное использование памяти вы могли бы первый индекс строки в файле:

  1. разобрать файл один раз и индекс позиция каждой строки в FileStream.
  2. Позвоните ReadLine() только в нужном месте.

например:

// Parse the file 
var indexes = new List<long>(); 
using (var fs = File.OpenRead("text.txt")) 
{ 
    indexes.Add(fs.Position); 
    int chr; 
    while ((chr = fs.ReadByte()) != -1) 
    { 
     if (chr == '\n') 
     {       
      indexes.Add(fs.Position); 
     } 
    } 
} 

int minLine = 21; 
int maxLine = 40; 

// Read the line 
using (var fs = File.OpenRead("text.txt")) 
{ 
    for(int i = minLine ; i <= maxLine ; i++) 
    { 
     fs.Position = indexes[ i ]; 
     using (var sr = new StreamReader(fs)) 
      Console.WriteLine(sr.ReadLine()); 

} 

Ура!

Смежные вопросы