source

Powershell의 빠르고 간단한 이진 연결 파일

lovecheck 2023. 8. 25. 23:44
반응형

Powershell의 빠르고 간단한 이진 연결 파일

파워셸을 사용하여 이진 파일을 연결하는 가장 좋은 방법은 무엇입니까?기억하기 쉽고 실행이 빠른 원라이너를 선호합니다.

제가 생각해낸 최고의 것은:

gc -Encoding Byte -Path ".\File1.bin",".\File2.bin" | sc -Encoding Byte new.bin

이것은 잘 작동하는 것처럼 보이지만 큰 파일에서는 매우 느립니다.

PowerShell을 사용하는 방법은 제가 PowerShell을 사용하는 방법입니다.그러나 성능을 향상시키려면 -ReadCount 매개 변수를 사용해야 합니다.또한 위치 매개 변수를 활용하여 이를 더욱 단축할 수 있습니다.

gc File1.bin,File2.bin -Encoding Byte -Read 512 | sc new.bin -Encoding Byte

편집자 참고 사항:크로스 플랫폼 PowerShell(Core) 버전(버전 6 이상)에서는-AsByteStream이제 대신 사용해야 합니다.-Encoding Byte또한, 그sccmdlet의 별칭이 제거되었습니다.

-ReadCount 매개변수의 사용과 관련하여, 저는 얼마 전에 사람들이 유용하다고 생각할 수 있는 블로그 게시물 - 대용량 파일에 대한 콘텐츠 가져오기 성능 최적화.

Powershell은 아니지만 Powershell이 있으면 다음 명령 프롬프트도 표시됩니다.

copy /b 1.bin+2.bin 3.bin

Keith Hill이 지적했듯이 Powershell 내부에서 실행해야 하는 경우 다음을 사용할 수 있습니다.

cmd /c copy /b 1.bin+2.bin 3.bin 

최근에 비슷한 문제가 있었습니다. 두 개의 대용량(2GB) 파일을 하나의 파일(4GB)에 추가해야 했습니다.

Get-Content에 대한 -ReadCount 매개 변수를 조정하려고 했지만 큰 파일의 성능을 향상시킬 수 없었습니다.

저는 다음과 같은 솔루션을 사용했습니다.

function Join-File (
    [parameter(Position=0,Mandatory=$true,ValueFromPipeline=$true)]
    [string[]] $Path,
    [parameter(Position=1,Mandatory=$true)]
    [string] $Destination
)
{
    write-verbose "Join-File: Open Destination1 $Destination"
    $OutFile = [System.IO.File]::Create($Destination)
    foreach ( $File in $Path ) {
        write-verbose "   Join-File: Open Source $File"
        $InFile = [System.IO.File]::OpenRead($File)
        $InFile.CopyTo($OutFile)
        $InFile.Dispose()
    }
    $OutFile.Dispose()
    write-verbose "Join-File: finished"
} 

성능:

  • cmd.exe /c copy file1+file2 File3약 5초(최적)
  • gc file1,file2 |sc file3약 1100초(요크)
  • join-file File1,File2 File3약 16초(OK)

성능은 사용되는 버퍼 크기에 따라 크게 달라집니다.기본적으로 상당히 작은 크기입니다.2GB 파일 2개를 연결하면 약 256kb의 버퍼 크기가 됩니다.크기를 크게 하면 때로는 실패하거나 작게 하면 드라이브의 처리 능력보다 더 적은 처리량을 얻을 수 있습니다.

와 함께gc그것으로-ReadCount단순한 것이 아닌-Read(PowerShell 5.0):

gc -ReadCount 256KB -Path $infile -Encoding Byte | ...

내가 찾은 것도Add-Content많은 작은 파일을 파일 단위로 저장하는 것이 더 낫습니다. 적당한 양의 데이터(200MB)만 파이프로 연결하면 컴퓨터가 정상적으로 작동하고 PowerShell이 동결되고 CPU가 가득 찼기 때문입니다.

비록 ~일지라도Add-Content대상 파일이 사용 중이라는 오류와 함께 수백 개의 파일에 대해 무작위로 몇 번 실패했기 때문에 잠시 루프와 시도 캐치를 추가했습니다.

# Empty the file first
sc -Path "$path\video.ts" -Value @() -Encoding Byte 
$tsfiles | foreach {    
    while ($true) {
        try { # I had -ReadCount 0 because the files are smaller than 256KB
            gc -ReadCount 0 -Path "$path\$_" -Encoding Byte | `
                Add-Content -Path "$path\video.ts" -Encoding Byte -ErrorAction Stop
            break;
        } catch {
        }
    }
}

파일 스트림을 사용하는 것이 훨씬 빠릅니다.는 " " " " " 로 할 수 .[System.IO.File]::Open하지만 당신은 할 수 있습니다.new [System.IO.FileStream] 예:

# $path = "C:\"
$ins = @("a.ts", "b.ts")
$outfile = "$path\out.mp4"
$out = New-Object -TypeName "System.IO.FileStream" -ArgumentList @(
    $outfile, 
    [System.IO.FileMode]::Create,
    [System.IO.FileAccess]::Write,
    [System.IO.FileShare]::None,
    256KB,
    [System.IO.FileOptions]::None)
try {
    foreach ($in in $ins) {
        $fs = New-Object -TypeName "System.IO.FileStream" -ArgumentList @(
            "$path\$in", 
            [System.IO.FileMode]::Open,
            [System.IO.FileAccess]::Read,
            [System.IO.FileShare]::Read,
            256KB,
            [System.IO.FileOptions]::SequentialScan)
        try {
            $fs.CopyTo($out)
        } finally {
            $fs.Dispose()
        }
    }
} finally {
    $out.Dispose()
}

언급URL : https://stackoverflow.com/questions/1783554/fast-and-simple-binary-concatenate-files-in-powershell

반응형