2015-01-01 3 views
1

У меня странная проблема, по которой я не могу найти решение. Я пытаюсь прочитать большие файлы (от 500 МБ до 2 ГБ) кусками 8М строк.File.ReadLines выбрасывает OutOfMemoryException

Для этого я создал следующее:

public static List<string> read_file(string path, Int32 start, Int32 end, Boolean is_big_file) 
{ 
    try 
    { 
     List<string> lines = new List<string>(); 

     if (is_big_file) 
      lines = File.ReadLines(path).Skip(start).Take(end - start).ToList(); 
     else 
      lines = File.ReadAllLines(path).ToList(); 

     return lines; 
    } 
    catch { return null; } 
} 

Если файл имеет меньше 8M линий, ReadAllLines используется, и все работает. Если файл больше, он будет использовать ReadLines.Skip.Take.

Первый кусок работает, я получаю первые 8 M строк. Старт = 0. конец = 8 000 000.

Второй кусок не работает. старт = 8,000,000. end = 16 000 000 или последняя строка файла (в зависимости от количества строк). По какой-то причине я получаю OutOfMemoryException, когда у меня есть менее 8M строк для чтения (end = 12,500,000).

У вас есть идеи, почему это происходит? Пропускает ли кеширует исходные строки? Есть ли более элегантное решение?

Спасибо!

+2

В каждом запросе, читающем любой последующий фрагмент, вы физически читаете все предыдущие строки (куски). Неудивительно, что он ест память, как сумасшедшую. Вам лучше работать с файлом с помощью StreamReader. –

+0

Могу ли я спросить: как вызывающий вызывающий этот метод для большого файла считывает несколько партий? Что удивительно для меня, так как ваш подход может быть чрезвычайно неэффективным **, File.ReadLines возвращает IEnumerable, который внутренне использует StreamReader (то же, что и принятый ответ ниже), чтобы читать по одной строке за раз. Если вы явно не держите большое количество строк в памяти или не делаете что-то еще неправильно, вам должно быть сложно получить исключение OOM (не исключено, хотя .. и опять же, этот подход, безусловно, неэффективен). –

+0

Если вы выполняете пакетную обработку строк только из-за опасений, что у вас есть большой файл для обработки, и все, что вам нужно сделать, это обрабатывать каждую строку один раз, по одной строке за раз, я бы рекомендовал вам сохранить его простым и просто используйте 'IEnumerable', возвращаемый методом ReadLines, для итерации по всем строкам. Все строки не должны загружаться, учитывая, как Iterator реализован с использованием' StreamReader' (нет необходимости повторно изобретать колесо, если я понимаю ваша потребность правильно). См. Http://referencesource.microsoft.com/#mscorlib/system/io/file.cs,d989485a49fbbfd2 –

ответ

1

На самом деле, с помощью этого:

File.ReadLines(path) 

Вы читаете ВСЕ линии. Вам лучше использовать FileStream и Seek в байтах, которые вы хотите прочитать. Что-то вроде этого:

using (FileStream fs = new FileStream(path, FileMode.Open)) 
{ 
    fs.Seek(start, SeekOrigin.Begin); 
    TextReader tr = new StreamReader(fs); 

    string line = tr.ReadLine(); 
} 
+0

Это сделало трюк. Большое спасибо! – Derorrist