2009-11-23 14 views
21

में फास्ट एंड सरल बाइनरी कॉन्सटेनेट फाइलें पावरहेल का उपयोग करके बाइनरी फाइलों को संयोजित करने का सबसे अच्छा तरीका क्या है? मैं एक-लाइनर पसंद करता हूं जो याद रखने के लिए आसान और निष्पादित करने के लिए तेज़ है।पावरहेल

सबसे अच्छा मैं के साथ आ गया है:

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

यह ठीक से काम करने लगता है, लेकिन बहुत बड़ी फ़ाइलों के साथ धीमी है।

उत्तर

25

जो दृष्टिकोण आप ले रहे हैं वह है जिस तरह से मैं इसे PowerShell में करूँगा। हालांकि आपको perf को बेहतर बनाने के लिए -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 सेकंड लेने में चला गया। यह एक x25m ड्राइव पर है। अच्छा लगा। आप मेरी स्वीकृति प्राप्त करते हैं। – FkYkko

+0

23 फाइलों पर फैले 4.4 जीबी आईएसओ में शामिल होने के लिए बस एक-लाइनर का इस्तेमाल किया। फ़ाइल ठीक से दोबारा इकट्ठा किया, और 1024 बाइट ब्लॉक का उपयोग कर अपने लैपटॉप पर 35 मिनट लग गए। –

+0

मैं इस काम का अनुमान लगा रहा हूं क्योंकि पाइप स्कैन करने के लिए .NET ऑब्जेक्ट भेज रहा है? जब मैंने एक सी प्रोग्राम में बाइनरी डेटा पाइप करने की कोशिश की, तो मैंने देखा कि मुझे केवल प्रत्येक बाइट के पहले 7 बिट मिल गए हैं, क्योंकि "|" एन्कोडिंग का आह्वान किया गया था। – johnnycrash

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 –

+0

अच्छा सरल समाधान, किसी भी विंडोज कंप्यूटर पर काम करता है। उपरोक्त लेकिन केथ को स्वीकार करते हैं क्योंकि मैंने पीएस संस्करण के लिए कहा था। Thx – FkYkko

+3

ध्यान दें कि 'कॉपी' वाइल्डकार्ड का समर्थन करता है। तो 'कॉपी/बी * .bin out.bin' आपकी सभी बिन-फाइलों को जोड़ देगा और आउटपुट बहुत तेज होगा (यानी PowerShell से बहुत तेज़)। –

3

मुझे हाल ही में एक ही समस्या थी, जहां मैं दो बड़ी (2 जीबी) फ़ाइलों को एक फ़ाइल (4 जीबी) में जोड़ना चाहता था।

मैंने गेट-कंटेंट के लिए -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 के आसपास सेकंड (सर्वश्रेष्ठ)
  • 1100 सेकंड (छी)
  • join-file File1,File2 File3 के आसपास चारों ओर gc file1,file2 |sc file3 16 सेकंड (ठीक)
+0

cmd.exe प्रति देशी पीएस cmdlets की तुलना में कई गुना तेज है - 1.2 एमबी/एस बनाम> 120 एमबी/एस। आश्चर्यजनक बात यह नहीं है कि रीडकाउंड पैरामीटर –

1

प्रदर्शन बफर आकार पर बहुत अधिक निर्भर है। वे डिफ़ॉल्ट रूप से काफी छोटे हैं। 2x2 जीबी फाइलों को जोड़ना मैं लगभग 256 केबी का बफर लेना चाहता हूं। बड़ी संख्या में जाकर कभी-कभी असफल हो जाते हैं, छोटे और आपको ड्राइव के मुकाबले कम थ्रूपुट मिल जाएगा।

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

प्लस मैं Add-Content पाया बेहतर और छोटे फ़ाइलों का एक बहुत कुछ के लिए फ़ाइल-दर-फ़ाइल जा रहा हो सकता है, क्योंकि पाइपिंग:

gc साथ

कि -ReadCount नहीं बस -Read (PowerShell 5.0) के साथ होगा केवल एक मामूली मात्रा में डेटा (200 एमबी) मैंने पाया कि मेरा कंप्यूटर ओम, पावरशेल फ्रीजिंग और सीपीयू पर पूरा हो रहा है।

हालांकि 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() 
} 
+0

के साथ गेट-कंटेंट कैसे काम करता है, यह अनुमान लगा रहा है कि यह cmd.exe copy कमांड द्वारा उपयोग की जाने वाली एक बहुत ही समान विधि है –