xuyunhai20160827 Ответов: 2

Выдает ошибку при считывании большого файла


I need to order according to the text of a line of text reading, when I read the file size of about 100MB in all normal, but when I read the file size is about 300MB when the memory error occurred.


деталь функции как показано ниже:
var filePath = @"D:\junk\test.txt";
var fileSize = new FileInfo(filePath).Length;
var viewSize = fileSize
List<string> rowArray = new List<string>();
using (var mm = MemoryMappedFile.CreateFromFile(filePath, FileMode.Open, null, 0, MemoryMappedFileAccess.Read))
using (var stream = mm.CreateViewStream(0, viewSize, MemoryMappedFileAccess.Read))
using (var reader = new StreamReader(stream, Encoding.UTF8))
{
    rowArray.Add(reader.ReadLine());
}

The rowArray is provided to the LISTVIEW data source, LISTVIEW uses a virtual mode


Что я уже пробовал:

I use the third party software to read the file, whether it is the size of 100MB or 300MB size, everything is normal


Why I don't use this method of File.ReadAllLines is that it takes 28 seconds to read the 300MB file, and the Third party software takes about 10 seconds
So I used the MemoryMappedFile technology, but unfortunately, the 300MB file size out of memory error.

OriginalGriff

Ответ обновлен - комментарии в данный момент не отображаются, это известная ошибка, и они работают над ней.

2 Ответов

Рейтинг:
2

Jochen Arndt

Общая память, которую могут использовать списки, ограничена 2 ГБ. При использовании .NET 4.5 или более поздней версии с 64-битными сборками этот предел может быть увеличен с помощью элемент <gcAllowVeryLargeObjects> [^].

Теперь вы можете спросить, почему вы сталкиваетесь с этим ограничением с файлами размером около 300 МБ.

У вас есть список строк. Строки используют внутреннюю кодировку UTF-16 (два байта на символ). Если ваш входной файл содержит только символы ASCII, то требуемая память для хранения строк в два раза больше размера файла.

В списке также должны храниться ссылки на все строки. Таким образом, у вас есть 4 байта (или 8 с 64-битными сборками) на строку.

Список будет расти во время чтения. Это требует перераспределения. При повторном выделении выделяется новая память, и текущее содержимое копируется до освобождения старой памяти. Во время таких операций вы, вероятно, получите исключение out of memory. Этого можно избежать, установив емкость списков, которая требует определения количества строк. Это позволяет избежать перераспределения и выделения памяти для большего количества строк, чем на самом деле требуется.

Решением вашей проблемы может быть использование списка, содержащего смещения строк для вашего файла, сопоставленного с памятью. Этот список будет использовать только 4 или 8 байт на строку. Поскольку вы используете виртуальное представление списка, извлеките строки в представлении с помощью смещений (расстояние до следующего смещения-это длина строки).


OriginalGriff

Это еще хуже - он отображает каждую строку отдельно в ListView... :OMG:

Jochen Arndt

Он использует виртуальное представление списка.

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

Рейтинг:
0

OriginalGriff

Почему ты все так усложняешь?
Вы создаете новый список строк, к которому добавляете одну строку: все текстовое содержимое файла, после сопоставления памяти и создания двух потоков формируете сопоставленный файл.
Что эквивалентно высказыванию:

List<string> rowArray = new List<string>();
rowArray.Add(File.ReadAllText(filePath));
Попробуйте это и посмотрите, исчезнет ли ваша проблема с памятью...

Мне нужно прочитать одну строку за другой и показать ее в ListView

Это не то, что делает ваш код, даже немного.
И это совершенно определенно не то, что вы хотите сделать вообще, и именно поэтому вы получаете ошибки "из памяти" - никогда не пытайтесь отобразить так много информации за один раз. Сколько строк текста вы ожидаете, что файл размером 100 Мб (или, что еще хуже, 300 МБ) будет содержать? Если среднее значение составляет 80 символов в строке - а обычно оно намного меньше, - это 1 250 000 строк для файла размером 100 МБ и 3 750 000 для файла большего размера. Как вы ожидаете, что ваш пользователь справится с этим, не говоря уже о системе? Каждая из этих строк является отдельным элементом управления в ListView! И вот почему у тебя кончается память!

Не делай этого. Страница, фильтр, поиск. Но просто бросать так много на пользователя и ожидать, что он справится с этим, лениво и приведет только к тому, что ваш пользователь вернет программное обеспечение и потребует свои деньги обратно...


xuyunhai20160827

Мне нужно прочитать одну строку за другой и показать ее в ListView

Philippe Mori

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

Кстати, зачем вы задаете вопрос, если не хотите слушать экспертов?.. 

xuyunhai20160827

Я только что попробовал ваш код, и у меня есть два вопроса.
1. тот же компьютер, открывающий файл размером 300 МБ, занимает около 28 секунд, в то время как стороннее программное обеспечение занимает всего около 10 секунд, я хочу сделать с производительностью то же самое, что и стороннее программное обеспечение.
2.Если вы используете ReadAllText или ReadAllLines для чтения данных и загрузки их в LISTVIEW, то я не могу знать ход загрузки.
Поэтому я использовал технологию MemoryMappedFile, самый быстрый способ чтения, но, к сожалению, размер файла 300 МБ из-за ошибки памяти.
а теперь, как сказать, спасибо за ваш ответ.

вы также можете прочитать эту Арктику
Ссылка как показано ниже:
http://stackoverflow.com/questions/4273699/how-to-read-a-large-1-gb-txt-file-in-net