Как вырезать раздел размером 1 ГБ из очень большого текстового файла (98 ГБ)?

418
Catsunami

Мне удалось создать файл журнала на 98 Гб во время ночной проверки. Я ничего не могу сделать с файлом 98GB. Первоначально я хотел разрезать его на более мелкие части, поэтому я попробовал 7-zip, но на самом деле у меня недостаточно места на диске (вероятно, потому что сейчас там есть файл объемом 100 ГБ ...). Так что я хочу отрезать только 1GB раздел с конца. Это возможно?

Это просто текстовый файл, который имеет временные метки и некоторые данные впоследствии, и мне все равно, будет ли первая строка в файле вырезана / искажена. Что-нибудь встроенное в Windows 10, которое я могу использовать?

4
Я не думаю, что есть какие-либо встроенные решения. Но сначала вы можете попробовать изменить размер файла подкачки или просто отключить hiberfil.sys, и у вас сразу же будет несколько ГБ для запуска `tail` в журнале. После этого просто удалите огромный файл журнала и измените размер файлов * .sys, если это необходимо. Или, если у вас есть другой диск, просто сохраните выходной файл там phuclv 6 лет назад 0
@phuclv, спасибо. Я воспользовался предложением Боба, и, очевидно, мои данные были в первом ГБ, остальные были только исключениями. Единственный другой доступный мне диск - это сетевой диск, и запись 98 ГБ, даже порциями, довольно дикая! Catsunami 6 лет назад 0
в этом случае просто [вызвать `SetEndOfFile`] (https://superuser.com/q/299329/241386) обрезать файл phuclv 6 лет назад 0
@phuclv, да, было бы проще, если бы я знал, что мне не нужны 97ГБ в конце. Однако я не был уверен, где проблема. Catsunami 6 лет назад 0

2 ответа на вопрос

2
Bob

Это также может быть выполнимо с помощью встроенных командлетов, но я бы опасался запускать Get-Contentфайлы размером более 100 МБ. Если вы хотите попробовать, вы можете захотеть эквивалент дляtail . Я не уверен, достаточно ли они умны, чтобы пропустить вперед, или они пытаются прочитать каждую строку с самого начала и отображать только последние X строк. Очевидно, что последний подход займет некоторое время, если он попытается прочитать и пропустить 90+ ГБ.

Если вас не интересуют инструменты, встроенные в Windows, я считаю, что tailреализация GNU умнее. Это может быть запущено из WSL или одного из множества портов.

Придерживаясь только сценариев PowerShell / .NET, я адаптирую предыдущий сценарий PowerShell, предназначенный для разделения одного большого файла. Этот сценарий был написан для использования блоков по 4 КБ, минимизируя использование памяти. Сначала мы можем найти правильное местоположение (почти мгновенная операция) и скопировать оттуда. Для простоты не выполняется синтаксический анализ следующего / предыдущего разрыва строки ; мы просто прыгаем на определенный байт (даже в середине строки).

Если вы предпочитаете искать определенное расстояние с самого начала, вы можете, например, заменить $seekLoc = 97GBи $seekOrigin = "Begin", и, возможно, $copyLen = 10GBбыть в безопасности и не пропустить конец.

$inFile = "foo.txt" $outFile = "bar.txt" $seekLoc = -1GB $seekOrigin = "End" $copyLen = 1GB  # need to sync .NET CurrentDirectory with PowerShell CurrentDirectory # https://stackoverflow.com/questions/18862716/current-directory-from-a-dll-invoked-from-powershell-wrong [Environment]::CurrentDirectory = Get-Location # 4k is a fairly typical and 'safe' chunk size # partial chunks are handled below $bytes = New-Object byte[] 4096  $inReader = [System.IO.File]::OpenRead($inFile) $inReader.Seek($seekLoc, $seekOrigin)  # better to use functions but a flag is easier in a simple script $finished = $false  $bytesToRead = $copyLen  # Just like File::OpenWrite except CreateNew instead to prevent overwriting existing files $outWriter = New-Object System.IO.FileStream "$outFile",CreateNew,Write,None  while ($bytesToRead) { # read up to 4k at a time, but no more than the remaining bytes from copyLen $bytesRead = $inReader.Read($bytes, 0, [Math]::Min($bytes.Length, $bytesToRead))  # 0 bytes read means we've reached the end of the input file if (!$bytesRead) { break }  $bytesToRead -= $bytesRead  $outWriter.Write($bytes, 0, $bytesRead) }  # dispose closes the stream and releases locks $outWriter.Dispose()  $inReader.Dispose() 
Спасибо за предложение, Боб. Это работало отлично. Данные, которые я хотел, были на самом деле в первом ГБ, остальные (все 97 ГБ) снова и снова заполнялись одним и тем же исключением (не моим программным обеспечением), пока не заполнили мой SSD и не разбились, прежде чем я вошел. Catsunami 6 лет назад 0
обратите внимание, что это записывает в другой файл, поэтому он не будет работать, если не хватает 1 ГБ свободного места. В большинстве случаев процесс записи часто не удается записать, потому что на диске не осталось места, и вы на самом деле не получаете журнал прямо перед его падением phuclv 6 лет назад 0
@phuclv. Там было достаточно места для блока размером 1 ГБ. Реально в большинстве случаев должна быть возможность освободить место на диске, чтобы сохранить чанк. Использование `tail`, как вы предлагали, позволило мне увидеть некоторые строки в конце, но не зная, сколько данных безопасно обрезать, я не мог просто обрезать файл. Catsunami 6 лет назад 0
1
harrymc

Я использовал V File Viewer, чтобы легко просматривать такие большие файлы с успехом. Это решение не потребует много места на диске, а просмотрщик очень быстрый.

V File Viewer - пробная версия с 30-дневным пробным периодом, а затем 20 долларов США, что включает 6 лет бесплатных обновлений. Если вам нужно время от времени анализировать такие большие текстовые файлы, это может стоить своей цены. Я заплатил и считаю это отличным вложением.

образ

Спасибо за предложение. Я предпочитаю решения, в которых мне не нужно устанавливать стороннее программное обеспечение, поэтому я принимаю ответ Боба. Catsunami 6 лет назад 0