2014-02-19 5 views
5

Если у вас есть файл csv, данные которого будут время от времени увеличиваться. Теперь мне нужно прочитать последние 30 000 строк.Прочтите последние 30 000 строк файла

Код:

string[] lines = File.ReadAllLines(Filename).Where(r => r.ToString() != "").ToArray(); 

int count = lines.Count(); 

int loopCount = count > 30000 ? count - 30000 : 0; 

    for (int i = loopCount; i < lines.Count(); i++) 
    { 
     string[] columns = lines[i].Split(','); 
     orderList.Add(columns[2]); 
    } 

Он работает нормально, но проблема в том,

File.ReadAllLines(Filename) 

Читать полный файл, который вызывает производительность отсутствие. Я хочу, чтобы что-то вроде этого читало только последние 30 000 строк, которые итерации через полный файл.

PS: Я использую .Net 3.5. Files.ReadLines() не существует в .Net 3.5

+4

http://stackoverflow.com/questions/4619735/how-to-read-last-n-lines-of-log-file http://stackoverflow.com/questions/398378/get-last-10 -line-of-very-large-text-file-10gb-c-sharp/398512 # 398512 – Ofiris

ответ

4

Вы можете использовать File.ReadLines() метод вместо использования File.ReadAllLines()

Из MSDN: File.ReadLines()

ReadLines и ReadAllLines отличаются следующим образом:
Когда вы используете ReadLines, вы можете начать перечисление коллекции строк до , вся коллекция возвращается; когда вы используете ReadAllLines, вы должны ждать, пока весь массив строк будет возвращен до того, как вы сможете получить доступ к массиву .

Поэтому, когда вы работать с очень большими файлами, ReadLines может быть более эффективным.

Решение 1:

 string[] lines = File.ReadAllLines(FileName).Where(r => r.ToString() != "").ToArray(); 

     int count = lines.Count(); 
     List<String> orderList = new List<String>(); 
     int loopCount = count > 30000 ? 30000 : 0; 

     for (int i = count-1; i > loopCount; i--) 
     { 
      string[] columns = lines[i].Split(','); 
      orderList.Add(columns[2]); 
     } 

Решение 2: если вы используете .NET Framework 3.5, как вы сказали в комментариях ниже, вы не можете использовать File.ReadLines() метод, как это avaialble так .NET 4.0 ,

Вы можете использовать StreamReader, как показано ниже:

 List<string> lines = new List<string>(); 
     List<String> orderList = new List<String>(); 
     String line; 
     int count=0; 
     using (StreamReader reader = new StreamReader("c:\\Bethlehem-Deployment.txt")) 
     { 
      while ((line = reader.ReadLine()) != null) 
      { 
       lines.Add(line); 
       count++; 
      } 
     } 

     int loopCount = (count > 30000) ? 30000 : 0; 

     for (int i = count-1; i > loopCount; i--) 
     { 
      string[] columns = lines[i].Split(','); 
      orderList.Add(columns[0]); 
     } 
+0

m используя .net 3.5. извините, я забыл упомянуть об этом –

+0

@ShujaatSiddiqui: проверьте мой отредактированный ответ. –

+0

@ShujaatSiddiqui: я думаю, что 'ReadLines()' только avaialble из .NET 4.0, вы можете использовать 'StreamReader' –

2

Вы можете использовать File.ReadLines, вы можете начать перечислять коллекцию строк перед возвратом всей коллекции.

После этого вы можете использовать linq, чтобы сделать вещи намного проще. Reverse будет отменять порядок сбора, а Take займет n. Теперь добавьте Reverse, чтобы получить последние n строк в оригинальном формате.

var lines = File.ReadLines(Filename).Reverse().Take(30000).Reverse(); 

Если вы используете .NET 3.5 или более ранней версии вы можете создать свой собственный метод, который работает так же, как File.ReadLines, как это. Вот код для метода, первоначально написанного @Jon

public IEnumerable<string> ReadLines(string file) 
{ 
    using (TextReader reader = File.OpenText(file)) 
    { 
     string line; 
     while ((line = reader.ReadLine()) != null) 
     { 
     yield return line; 
     } 
    } 
} 

Теперь вы можете использовать linq над этой функцией, а также как выше заявление.

var lines = ReadLines(Filename).Reverse().Take(30000).Reverse(); 
+2

'ReadAllLines' читает все строки, что делать, если файл большой? – Ofiris

+0

@Ofiris смотрите обновленное сообщение .. :) – Sachin

+0

m используя .net 3.5. жаль, что я забыл упомянуть об этом –

0

Или у меня есть отличное видео для этого.

Попробуйте разделить csv на категории, такие как A-D, E-G .... и получите доступ к первому персонажу.

Или вы можете разделить данные со счетом entites. Например, каждый файл будет содержать 15 000 пользователей. И это текстовый файл, который будет содержать крошечные данные о entits и месте, как:

Txt файла:

entitesID | inWhich.Csv 
.... 
1

Проблема заключается в том, что вы не знаете, где начать чтение файла, чтобы получить последние 30000 строк. Если вы не хотите поддерживать отдельный индекс смещений строк, вы можете либо прочитать файл из строк подсчета, только сохраняя последние 30 000 строк, либо можете начинать с строк конца счета назад. Последний подход может быть эффективным, если файл очень большой, и вам нужно только несколько строк. Тем не менее, 30 000 не кажется «несколько строк», так вот это подход, который считывает файл с самого начала и использует очередь, чтобы сохранить последние 30000 строк:

var filename = @" ... "; 
var linesToRead = 30000; 
var queue = new Queue<String>(); 
using (var streamReader = File.OpenText(fileName)) { 
    while (!streamReader.EndOfStream) { 
    queue.Enqueue(streamReader.ReadLine()); 
    if (queue.Count > linesToRead) 
     queue.Dequeue(); 
    } 
} 

Теперь вы можете получить доступ к линии, которые хранится в queue. Этот класс реализует IEnumerable<String>, позволяющий использовать foreach для повторения строк. Однако, если вам нужен произвольный доступ, вам придется использовать метод ToArray для преобразования очереди в массив, который добавляет некоторые издержки для вычисления.

Это решение является эффективным с точки зрения памяти, поскольку в памяти должно храниться не более 30 000 строк, и сборщик мусора может освобождать любые дополнительные линии, когда это необходимо. Использование File.ReadAllLines приведет к вытаскиванию всех строк в память сразу, что увеличит объем памяти, необходимый для процесса.

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