Это также может быть выполнимо со встроенными командлетами, но я бы с осторожностью запускал 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()