У меня есть прекрасная задача разработать, как обрабатывать большие файлы, загружаемые в редактор сценариев нашего приложения (это похоже на VBA для нашего внутреннего продукта для быстрых макросов). Большинство файлов имеют размер около 300-400 КБ, что нормально загружается. Но когда они превышают 100 МБ, у процесса возникают проблемы (как и следовало ожидать).
Что происходит, так это то, что файл читается и помещается в RichTextBox, по которому затем выполняется навигация - не беспокойтесь об этой части.
Разработчик, написавший исходный код, просто использует StreamReader и выполняет
[Reader].ReadToEnd()
что может занять некоторое время.
Моя задача - разбить этот фрагмент кода, прочитать его по частям в буфер и показать индикатор выполнения с возможностью его отмены.
Некоторые предположения:
- Большинство файлов будут 30-40 МБ
- Содержимое файла - текстовое (не двоичное), некоторые - формат Unix, некоторые - DOS.
- Как только содержимое получено, мы выясняем, какой терминатор используется.
- Когда он загружен, никого не волнует время, необходимое для рендеринга в richtextbox. Это всего лишь начальная загрузка текста.
Теперь вопросы:
- Могу ли я просто использовать StreamReader, затем проверить свойство Length (так ProgressMax) и выполнить Read для заданного размера буфера и выполнить итерацию в цикле while WHILST внутри фонового рабочего, чтобы он не блокировал основной поток пользовательского интерфейса? Затем верните конструктор строк в основной поток после его завершения.
- Содержимое будет отправлено в StringBuilder. могу ли я инициализировать StringBuilder размером потока, если длина доступна?
Это (по вашему профессиональному мнению) хорошие идеи? В прошлом у меня было несколько проблем с чтением контента из Streams, потому что он всегда будет пропускать последние несколько байтов или что-то в этом роде, но я задам другой вопрос, если это так.
источник
Ответы:
Вы можете улучшить скорость чтения, используя BufferedStream, например:
ОБНОВЛЕНИЕ за март 2013 г.
Недавно я написал код для чтения и обработки (поиска текста в) текстовых файлов размером 1 ГБ (намного больше, чем файлы, используемые здесь) и добился значительного прироста производительности за счет использования шаблона производитель / потребитель. Задача производителя считывает строки текста с помощью
BufferedStream
и передает их отдельной задаче-потребителю, которая выполняет поиск.Я использовал это как возможность изучить TPL Dataflow, который очень хорошо подходит для быстрого кодирования этого шаблона.
Почему BufferedStream быстрее
ОБНОВЛЕНИЕ ДЕКАБРЯ 2014 ГОДА: Ваш пробег может отличаться
Судя по комментариям, FileStream должен использовать BufferedStream внутри. Когда этот ответ был впервые предоставлен, я измерил значительный прирост производительности, добавив BufferedStream. В то время я ориентировался на .NET 3.x на 32-битной платформе. Сегодня, ориентируясь на .NET 4.5 на 64-битной платформе, я не вижу никаких улучшений.
Связанный
Я столкнулся со случаем, когда потоковая передача большого сгенерированного файла CSV в поток ответов из действия ASP.Net MVC была очень медленной. Добавление BufferedStream в этом случае повысило производительность в 100 раз. Подробнее см. Очень медленный небуферизованный вывод.
источник
Если вы прочитаете статистику производительности и тестов на этом веб-сайте , вы увидите, что самый быстрый способ чтения (поскольку чтение, запись и обработка - все разные) текстовый файл - это следующий фрагмент кода:
Всего было оценено около 9 различных методов, но в большинстве случаев этот, кажется, опережает других, даже не выполняя буферизованного считывателя, как упоминали другие читатели.
источник
StringBuilder
для загрузки их в память, загружается быстрее, поскольку он не создает новую строку каждый раз, когда вы добавляете символы)Вы говорите, что вас попросили показать индикатор выполнения во время загрузки большого файла. Это потому, что пользователи искренне хотят видеть точный% загрузки файла, или просто потому, что им нужна визуальная обратная связь о том, что что-то происходит?
Если последнее верно, то решение становится намного проще. Просто сделайте
reader.ReadToEnd()
это в фоновом потоке и отобразите индикатор выполнения в виде маркера вместо правильного.Я поднимаю этот вопрос, потому что, по моему опыту, это часто бывает. Когда вы пишете программу обработки данных, пользователей определенно заинтересует цифра в% полной, но для простых, но медленных обновлений пользовательского интерфейса они, скорее всего, просто захотят знать, что компьютер не разбился. :-)
источник
StreamReader
циклу. Тем не менее, это все равно будет проще, потому что нет необходимости заранее читать, чтобы рассчитать индикатор прогресса.Для двоичных файлов самый быстрый способ их чтения, который я нашел, - это.
В моих тестах это в сотни раз быстрее.
источник
Используйте фоновый воркер и прочтите только ограниченное количество строк. Читать дальше, только когда пользователь прокручивает.
И постарайтесь никогда не использовать ReadToEnd (). Это одна из функций, о которых вы думаете «зачем они это сделали?»; это помощник для детей-скриптов, который отлично справляется с мелочами, но, как видите, с большими файлами он отстой ...
Тем, кто говорит вам использовать StringBuilder, нужно чаще читать MSDN:
Вопросы
производительности Оба метода Concat и AppendFormat объединяют новые данные с существующим объектом String или StringBuilder. Операция конкатенации объектов String всегда создает новый объект из существующей строки и новых данных. Объект StringBuilder поддерживает буфер для объединения новых данных. Новые данные добавляются в конец буфера, если место доступно; в противном случае выделяется новый буфер большего размера, данные из исходного буфера копируются в новый буфер, а затем новые данные добавляются в новый буфер. Производительность операции конкатенации для объекта String или StringBuilder зависит от того, как часто происходит выделение памяти.
Операция конкатенации String всегда выделяет память, тогда как операция конкатенации StringBuilder выделяет память только в том случае, если буфер объекта StringBuilder слишком мал для размещения новых данных. Следовательно, класс String предпочтительнее для операции конкатенации, если конкатенация фиксированного числа объектов String. В этом случае отдельные операции конкатенации могут даже быть объединены компилятором в одну операцию. Объект StringBuilder предпочтительнее для операции конкатенации, если конкатенация произвольного числа строк; например, если цикл объединяет случайное количество строк пользовательского ввода.
Это означает огромное распределение памяти, что превращается в большое использование файловой системы подкачки, которая имитирует разделы вашего жесткого диска, чтобы действовать как оперативная память, но жесткий диск работает очень медленно.
Параметр StringBuilder отлично подходит для тех, кто использует систему как монопользователь, но когда у вас есть два или более пользователей, читающих большие файлы одновременно, у вас возникают проблемы.
источник
Этого должно быть достаточно, чтобы вы начали.
источник
Взгляните на следующий фрагмент кода. Вы упомянули
Most files will be 30-40 MB
. Это утверждает, что чтение 180 МБ за 1,4 секунды на Intel Quad Core:Оригинальная статья
источник
Возможно, вам лучше использовать здесь обработку файлов с отображением в память. Поддержка файлов с отображением в память будет присутствовать в .NET 4 (я думаю ... я слышал это от кого-то другого, говорящего об этом), следовательно, эта оболочка, которая использует p / вызывает то же самое.
Изменить: см. Здесь, в MSDN, как это работает, здесь запись в блоге, показывающая, как это делается в предстоящем .NET 4, когда он выйдет в виде релиза. Ссылка, которую я дал ранее, представляет собой оболочку вокруг pinvoke для достижения этой цели. Вы можете отобразить весь файл в память и просматривать его как скользящее окно при прокрутке файла.
источник
Всем отличных ответов! однако для тех, кто ищет ответ, они кажутся неполными.
Поскольку стандартная строка может иметь только размер X, от 2 ГБ до 4 ГБ в зависимости от вашей конфигурации, эти ответы на самом деле не соответствуют вопросу OP. Один из способов - работать со списком строк:
Некоторые могут захотеть токенизировать и разделить строку при обработке. Список строк теперь может содержать очень большие объемы текста.
источник
Итератор может быть идеальным для такого типа работы:
Вы можете вызвать это, используя следующее:
По мере загрузки файла итератор будет возвращать номер выполнения от 0 до 100, который вы можете использовать для обновления индикатора выполнения. После завершения цикла StringBuilder будет содержать содержимое текстового файла.
Кроме того, поскольку вам нужен текст, мы можем просто использовать BinaryReader для чтения символов, что обеспечит правильное выравнивание ваших буферов при чтении любых многобайтовых символов ( UTF-8 , UTF-16 и т. Д.).
Все это делается без использования фоновых задач, потоков или сложных настраиваемых конечных автоматов.
источник
Мой файл превышает 13 ГБ:
Следующая ссылка содержит код, который легко читает фрагмент файла:
Прочитать большой текстовый файл
Больше информации
источник