2009-11-23 167 views
21

使用Powershell連接二進制文件的最佳方式是什麼? 我更喜歡簡單易記的快速執行的單線程。Powershell中快速簡單的二進制連接文件

我想出的最好的是:

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

這似乎是工作正常,但與大文件非常慢。

回答

25

您採用的方法是我在PowerShell中執行此操作的方式。但是,您應該使用-ReadCount參數來提高性能。您也可以利用位置參數,以進一步縮短這個:

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

關於使用-ReadCount參數的,我做了這個博客中,而以前,人們可能會發現有用 - Optimizing Performance of Get Content for Large Files

+2

我只是跑這對我的示例文件和命令採取9分鐘3秒鐘,列入-read PARAM的去了。這是一個x25米的驅動器。尼斯。你得到我的接受。 – FkYkko 2009-11-23 15:36:20

+0

只用一行就可以加入一個跨越23個文件的4.4gb iso。重新組裝好文件,並使用1024字節塊在筆記本上花了35分鐘。 – 2012-07-12 21:56:27

+0

我猜這是有效的,因爲管道發送.net對象sc?當我試圖將二進制數據傳輸到c程序​​時,我注意到我只獲得每個字節的前7位,因爲「|」調用編碼。 – johnnycrash 2014-07-14 21:52:49

20

這不是PowerShell中,但如果你有PowerShell的你也有命令提示符:

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

正如基思·希爾指出,如果你真的需要從內部PowerShell中運行它,你可以使用:

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

副本中的cmd.exe固有的命令。你將不得不執行cmd/c copy/b 1.bin + 2.bin 3.bin – 2009-11-23 15:13:43

+0

好的簡單解決方案,適用於任何Windows計算機。 Upvoted,但接受基思,因爲我問PS版本。 Thx – FkYkko 2009-11-23 15:38:51

+3

還要注意'copy'支持通配符。因此,'copy/b * .bin out.bin'將連接所有bin文件,輸出速度非常快(即比使用PowerShell快得多)。 – 2014-04-13 12:09:23

3

我最近有一個類似的問題,我想將兩個大的(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)
+0

cmd.exe拷貝比原生PS cmdlet快很多倍 - 1.2MB/s與> 120Mb/s。並不奇怪考慮獲取內容是如何工作的,甚至與-ReadCound參數 – 2017-10-23 20:13:25

1

性能很大程度上取決於所使用的緩衝區大小。這些默認情況下相當小。連接2x2GB文件我會採用大約256kb的緩衝區大小。越大,有時會失敗,越小,吞吐量就會比驅動器的吞吐量降低。

隨着gc這會是與-ReadCount不是簡單-Read(PowerShell的5.0):

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

另外,我發現Add-Content要更好,要文件通過文件進行了大量的小文件,因爲管道只有適量的數據(200MB),我發現我的計算機正在運行,PowerShell凍結且CPU處於充滿狀態。

雖然Add-Content隨機失敗幾百文件幾次有關目標文件正在使用中的錯誤,所以我加了一個while循環和嘗試捕捉:

# 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() 
} 
+0

一個是猜測,這是由cmd.exe的複製命令使用一個非常類似的方法 – 2017-10-23 20:14:59