zoukankan      html  css  js  c++  java
  • Windows下使用powershell切割或合并文件

    # Obtain a suitable buffer length by partial file length
    function Get-BufferLength ([int]$partialFileLength)
    {
        [int]$MinBufferLength = 1MB
        # No need to consume great amount memory,initialize as 50M, you can adjust it from here.
        [int]$MaxBufferLength = 50MB
     
        if($partialFileLength -ge 1GB) { return $MaxBufferLength}
        elseif( $partialFileLength -le 50MB) { return $MinBufferLength }
        else{ return [int]( $MaxBufferLength/1GB * $partialFileLength )}
    }
     
    # Write partial stream to file from current position
    function Write-PartialStreamToFile
    {
        param(
        [IO.FileStream]$stream,
        [long]$length,
        [string]$outputFile
        )
     
        #copy stream to file
        function Copy-Stream( [int]$bufferLength )
        {
            [byte[]]$buffer = New-Object byte[]( $bufferLength )
     
            # Read partial file data to memory buffer
            $stream.Read($buffer,0,$buffer.Length) | Out-Null
     
            # Flush buffer to file
            $outStream = New-Object IO.FileStream($outputFile,'Append','Write','Read')
            $outStream.Write($buffer,0,$buffer.Length)
            $outStream.Flush()
            $outStream.Close()
        }
     
        $maxBuffer = Get-BufferLength $length
        $remBuffer = 0
        $loop = [Math]::DivRem($length,$maxBuffer,[ref]$remBuffer)
     
        if($loop -eq 0)
        {
            Copy-Stream $remBuffer
            return
        }
     
        1..$loop | foreach {
            $bufferLength = $maxBuffer
     
            # let last loop contains remanent length
            if( ($_ -eq $loop) -and ($remBuffer -gt 0) ) 
            {
                $bufferLength = $maxBuffer + $remBuffer
             }
             Copy-Stream  $bufferLength
     
             # show outer progress
             $progress = [int]($_*100/$loop)
             write-progress -activity 'Writting file' -status 'Progress' -id 2 -percentcomplete $progress -currentOperation "$progress %"
        }
    }
     
    # split a large file into mutiple parts by part count or part length
    function Split-File
    {
        param(
        [Parameter(Mandatory=$True)]
        [IO.FileInfo]$File,
        [Switch]$ByPartCount,
        [Switch]$ByPartLength,
        [int]$PartCount,
        [int]$PartLength,
        [IO.DirectoryInfo]$OutputDir = '.'
        )
     
        # Argument validation
        if(-not $File.Exists) { throw "Source file [$File] not exists" }
        if(-not  $OutputDir.Exists) { mkdir $OutputDir.FullName | Out-Null}
        if( (-not $ByPartCount) -and (-not $ByPartLength) )
        {
            throw 'Must specify one of parameter, [ByPartCount] or [ByPartLength]'
        }
        elseif( $ByPartCount )
        {
            if($PartCount -le 1) {throw '[PartCount] must larger than 1'}
            $PartLength = $File.Length / $PartCount
        }
        elseif( $ByPartLength )
        {
            if($PartLength -lt 1) { throw '[PartLength] must larger than 0' }
            if($PartLength -ge $File.Length) { throw '[PartLength] must less than source file' }
            $temp = $File.Length /$PartLength
            $PartCount = [int]$temp
            if( ($File.Length % $PartLength) -gt 0 -and ( $PartCount -lt $temp ) )
            {
              $PartCount++
            }
        }
     
        $stream = New-Object IO.FileStream($File.FullName,
        [IO.FileMode]::Open ,[IO.FileAccess]::Read ,[IO.FileShare]::Read )
     
        # Make sure each part file name ended like '001' so that it's convenient to merge
        [string]$numberMaskStr = [string]::Empty.PadLeft( [int]([Math]::Log10($PartCount) + 1), "0" )
     
        1 .. $PartCount | foreach {
             $outputFile = Join-Path $OutputDir ( "{0}.part_{1} " -f $File.Name , $_.ToString( $numberMaskStr ) )
             # show outer progress
             $progress = [int]($_*100/$PartCount)
             write-progress -activity "Splitting file" -status "Progress $progress %" -Id 1 -percentcomplete $progress -currentOperation "Handle file $outputFile"
             if($_ -eq $PartCount)
             {
                Write-PartialStreamToFile $stream ($stream.Length - $stream.Position) $outputFile
             }
             else
             {
             Write-PartialStreamToFile $stream $PartLength  $outputFile
             }
        }
        $stream.Close()
    }
     
    function Merge-File
    {
        param(
        [Parameter(Mandatory=$True)]
        [IO.DirectoryInfo]$SourceDir,
        [string]$Filter,
        [IO.FileInfo]$OutputFile
        )
     
        # arguments validation
        if ( -not $SourceDir.Exists ) { throw "Directory $SourceDir not exists." }
        $files = dir $SourceDir -File -Filter $Filter
        if($files -eq $null){ throw "No matched file in directory $SourceDir"}
     
        # output stream
        $outputStream = New-Object IO.FileStream($OutputFile.FullName,
            [IO.FileMode]::Append ,[IO.FileAccess]::Write ,[IO.FileShare]::Read )
     
        # merge file
        $files | foreach{
            #input stream
            $inputStream = New-Object IO.FileStream($_.FullName,
            [IO.FileMode]::Open ,[IO.FileAccess]::Read ,[IO.FileShare]::Read )
     
            $bufferLength = Get-BufferLength -partialFileLength $_.Length
            while($inputStream.Position -lt $inputStream.Length)
            {
                if( ($inputStream.Position + $bufferLength) -gt $inputStream.Length)
                {
                    $bufferLength = $inputStream.Length - $inputStream.Position
                }
     
                # show outer progress
                $progress = [int]($inputStream.Position *100/ $inputStream.Length)
                write-progress -activity 'Merging file' -status "Progress $progress %"  -percentcomplete $progress
     
                # read file to memory buffer
                $buffer= New-Object byte[]( $bufferLength )
                $inputStream.Read( $buffer,0,$buffer.Length) | Out-Null
     
                #flush buffer to file
                $outputStream.Write( $buffer,0,$buffer.Length) | Out-Null
                $outputStream.Flush()
            }
            $inputStream.Close()
        }
        $outputStream.Close()}
    使用示例
    # 先导入 函数 Split-Merge-File
    . 'ESplit-Merge-File.ps1' #注意句号和脚本之间有空格
     
    # 将文件 ‘E:win2012.vhdx’ 分割成20个小文件,输出至目录 'E:VHD'
    Split-File -File 'E:win2012.vhdx' -ByPartCount -PartCount 20 -OutputDir 'E:VHD'
     
    # 将件‘E:win2012.vhdx’按照每个大小 500MB 来分割,输出至目录 'E:VHD'
    Split-File -File 'E:win2012.vhdx' -ByPartLength -PartLength 500MB -OutputDir 'E:VHD'
     
    # 将 'E:VHD' 目录下包含 part 的所有文件合并,输出为 单个文件 'E:win2012-2.vhdx'
    Merge- File -SourceDir 'E:VHD' -Filter "*part*" -OutputFile 'E:win2012-2.vhdx'
  • 相关阅读:
    杂想
    验证码再次学习。(处理方法汇总)
    神经网络学习入门 -01
    基于本地文字提取的有效的定位和识别场景文字
    C#学习总结~~~
    Deep Learning!!!
    记事本也能批量更名
    家庭一台电脑多人上网方法
    基于 OS X Mavericks 系统
    关于中文编程是解决中国程序员效率的秘密武器的问题思考
  • 原文地址:https://www.cnblogs.com/qiushuiblog/p/11510896.html
Copyright © 2011-2022 走看看