Создайте небольшой файл (.txt или .TMP) из огромного файла .TMP
Ошибка "System.OutOfMemoryException" при создании небольшого файла из большого файла.
Обычно я использую приведенную ниже команду PowerShell для создания небольшой версии огромного файла,
Get-Content input_file_name.Tmp -TotalCount 100 | Out-File -Encoding Default "output_file_name_100.Tmp"
Однако это вызывает ошибку System.OutOfMemoryException. Какие-нибудь советы по этому поводу?
Примечание: раньше это работало для файлов большего размера. Думаю, проблема не в размере файла.
1 ответ
Я знаю, что вы лично думаете, что размер файла не может быть реальной проблемой, но стоит пересмотреть основы в интересах других читателей.
Get-Content
при использовании в конвейере считывает строки из файла по одной за раз.
Эта обработка по одному объекту является основной функцией конвейера PowerShell и действует как дроссель памяти (нет необходимости считывать весь ввод в память сразу.
Есть только три сценария, гдеGet-Content
считывает весь файл в память:
Если вы захватите
Get-Content
вывод в переменной ($content = Get-Content ...
), и в этом случае переменная получает массив, состоящий из всех строк.Если вы заключите
Get-Content
вызывать(...)
,$(...)
, или@(...)
, который также возвращает массив всех строк.Если вы используете
-Raw
переключатель, который делаетGet-Content
вернуть одну многострочную строку.
С помощью -TotalCount 100
(или -First 100
) не меняет этого фундаментального поведения: после 100
строки были прочитаны, Get-Content
прекращает чтение и закрывает файл.
Поэтому код в вашем вопросе не объясняет ваш симптом - у вас не должно быть нехватки памяти - по крайней мере, не потому, что входной файл большой; если это все еще происходит, возможно, вы видите ошибку.
Если у вас есть воспроизводимый случай, я рекомендую вам сообщить об ошибке на форуме Windows PowerShell UserVoice или, если вы можете (также) воспроизвести ошибку в PowerShell [Core] v6+, в репозитории PowerShell Core GitHub.
А пока вы можете рассмотреть возможность использования.NET напрямую, что также обычнобыстрее, чем использование командлетов PowerShell:
[Linq.Enumerable]::Take([IO.File]::ReadLines("$PWD/input_file_name.Tmp"), 100) |
Out-File -Encoding Default output_file_name_100.Tmp
Примечание:
• Использование"$PWD/"
как часть пути к входному файлу, поскольку рабочий каталог.NET обычно отличается от каталога PowerShell.
• В литералах типа PowerShell ([...]
), System.
часть полного имени типа может быть опущена; таким образом[Linq.Enumerable]
относится к System.Linq.Enumerable
, а также [IO.File]
к System.IO.File