8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

在 Powershell 中快速简单地连接二进制文件

David Hermansson 1月前

17 0

使用 Powershell 连接二进制文件的最佳方法是什么?我更喜欢简单易记且执行速度快的单行代码。我想到最好的方法是:gc -Encoding Byte -Path \'.\F...

使用 Powershell 连接二进制文件的最佳方法是什么?我更喜欢简单易记、执行速度快的单行代码。

我想到的最好的办法是:

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

这似乎可以正常工作,但是对于大文件来说速度非常慢。

帖子版权声明 1、本帖标题:在 Powershell 中快速简单地连接二进制文件
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由David Hermansson在本站《powershell》版块原创发布, 转载请注明出处!
最新回复 (0)
  • 您采用的方法是我在 PowerShell 中采用的方法。但是,您应该使用 -ReadCount 参数来提高性能。您还可以利用位置参数进一步缩短此时间:

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

    Editor's note : In the cross-platform PowerShell(核心) edition (version 6 and up), -AsByteStream must now be used instead of -Encoding Byte ; also, the sc alias for the Set-Content cmdlet has been removed.

    关于 -ReadCount 参数的使用,我之前写了一篇博客文章,大家可能会觉得有用 - 优化获取大文件内容的性能 .

  • 我刚刚在我的示例文件上运行了这个命令,在包含 -read 参数的情况下,命令从 9 分钟缩短到 3 秒。这是在 x25m 驱动器上。很好。你得到了我的认可。

  • 只需使用您的一行代码即可将 4.4gb 的 iso 合并到 23 个文件中。重新组合文件后一切正常,在我的笔记本电脑上使用 1024 字节块花了 35 分钟。

  • 我猜这是因为管道正在将 .net 对象发送到 sc?当我尝试将二进制数据传输到 ac 程序时,我注意到我只获得了每个字节的前 7 位,因为 \'|\' 调用了编码。

  • dbf 1月前 0 只看Ta
    引用 6

    在 PowerShell 6/7 中不再有效。字节不是可接受的编码。Get-Content:无法处理参数“Encoding”上的参数转换。“字节”不是受支持的编码名称。有关定义自定义编码的信息,请参阅 Encoding.RegisterProvider 方法的文档。(参数“名称”)

  • 它不是 Powershell,但是如果你有 Powershell 你也会有命令提示符:

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

    正如 Keith Hill 指出的那样,如果您确实需要从 Powershell 内部运行它,您可以使用:

    cmd /c copy /b 1.bin+2.bin 3.bin 
    
  • copy 是 cmd.exe 中的一个固有命令。您必须执行 cmd /c copy /b 1.bin+2.bin 3.bin

  • 简单实用的解决方案,适用于任何 Windows 电脑。已投赞成票,但接受 Keith 的意见,因为我要求 PS 版本。谢谢

  • 还要注意,copy 支持通配符。因此 copy /b *.bin out.bin 将连接所有 bin 文件,并且输出将非常快(即比使用 PowerShell 快得多)。

  • 谢谢……它比公认的答案快了大约十亿倍;)。当我尝试从 PowerShell 运行它时,我错过了 \'cmd /c\'。有时老方法仍然是最好的。

  • 我最近遇到了类似的问题,我想将两个大文件(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 秒(正常)
  • cmd.exe 复制速度比原生 PS cmdlet 快很多倍 - 1.2MB/s 对 >120Mb/s。考虑到 Get-Content 即使在使用 -ReadCound 参数的情况下也能正常工作,这并不奇怪

  • 性能在很大程度上取决于所使用的缓冲区大小。默认情况下,缓冲区大小相当小。连接 2x2GB 文件时,我会使用大约 256kb 的缓冲区大小。缓冲区过大有时会失败,缓冲区过小则会获得比驱动器所能承受的吞吐量更低的吞吐量。

    有了 gc 它就不仅仅是 -ReadCount -Read PowerShell 5.0):

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

    另外,我发现 Add-Content 对大量小文件进行逐个文件处理效果更好,因为只传输中等量的数据(200MB)时,我发现我的计算机出现 OOM、PowerShell 冻结并且 CPU 已满。

    尽管 Add-Content 对于几百个文件来说随机失败了几次,并出现有关目标文件正在使用的错误,所以我添加了一个 while 循环和一个 try catch:

    # 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()
    }
    
  • 您还可以使用此方法来连接任何类型的文件。
    不是那么快,但只是另一种方法

    cmd /c type file1 file2 file3 file4 > outfile
    

    或者,如果存在多个复制任务,您可以使用作业来加快速度。

    $jobs=@()
    $Files=@( @("d:\path\app1.rar","d:\path\app2.rar","d:\path\app3.rar","d:\path\appOutFile.rar"),@("c:\users\user\desktop\file1.iso","c:\users\user\desktop\file2.iso","c:\users\user\desktop\file3.iso","c:\users\user\desktop\isoOutFile.iso"),@("c:\users\user\video\video1.mp4","c:\users\user\video\video2.mp4","c:\users\user\video\mp4OutFile.mp4"))
    $totalMb=0
    foreach($Group in $Files){
        $sources=$Group|select -first ($Group.Length-1)
        $sources|%{ $totalMb+=(get-Item $_).Length/1mb }
        $sources=$(($sources -replace "^|$",[char]34)-join"+")
        $destination=[char]34+($Group|select -last 1)+[char]34
        cmd /c type nul> $destination
        $jobs+=start-job -scriptBlock { param($src,$dst) &cmd.exe "/c copy /b $src $dst" } -arg $sources,$destination 
        # $jobs+=start-job -scriptBlock { param($src,$dst) &cmd.exe "/c type $($src -replace '`"\+`"','`" `"') > $dst" } -arg $sources,$destination
    }
    
    "Total MegaBytes To Concatenate is: $( [math]::Truncate($totalMb) )MB"
    while ( $($jobs|% {$_.state -eq "running"}) -contains $true ) {"still concatenating files...";start-sleep -s 2}
    
    "jobs finished !!!";$jobs|receive-job;$jobs|remove-job -force
    
返回
作者最近主题: