PowerShell 脚本 比较两文件差异(带粗狂进度条第二版本优化)并汇总输出

一上来就放代码(下面已更新)

function Compare-FileHex {
    param (
        [Parameter(Mandatory=$true)]
        [string]$SourceFile,

        [Parameter(Mandatory=$true)]
        [string]$CompareFile,

        [Parameter(Mandatory=$false)]
        [string]$OutputFile,

        [Parameter(Mandatory=$false)]
        [int]$BufferSize = 1MB
    )

    function Format-FileSize {
        param ([long]$Size)
        if ($Size -ge 1GB) { "{0:N2} GB" -f ($Size / 1GB) }
        elseif ($Size -ge 1MB) { "{0:N2} MB" -f ($Size / 1MB) }
        elseif ($Size -ge 1KB) { "{0:N2} KB" -f ($Size / 1KB) }
        else { "$Size Bytes" }
    }

    $sourceStream = [System.IO.File]::OpenRead($SourceFile)
    $compareStream = [System.IO.File]::OpenRead($CompareFile)

    $results = New-Object System.Collections.Generic.List[PSCustomObject]
    $buffer1 = New-Object byte[] $BufferSize
    $buffer2 = New-Object byte[] $BufferSize

    $totalLength = [Math]::Max($sourceStream.Length, $compareStream.Length)
    $position = 0

    $sourceSize = $sourceStream.Length
    $compareSize = $compareStream.Length

    try {
        while ($position -lt $totalLength) {
            $read1 = $sourceStream.Read($buffer1, 0, $BufferSize)
            $read2 = $compareStream.Read($buffer2, 0, $BufferSize)

            $maxRead = [Math]::Max($read1, $read2)

            for ($i = 0; $i -lt $maxRead; $i++) {
                $sourceByte = if ($i -lt $read1) { $buffer1[$i] } else { $null }
                $compareByte = if ($i -lt $read2) { $buffer2[$i] } else { $null }
                
                if ($sourceByte -ne $compareByte) {
                    $results.Add([PSCustomObject]@{
                        Address = $position + $i
                        SourceFile = if ($sourceByte -ne $null) { "{0:X2}" -f $sourceByte } else { "--" }
                        CompareFile = if ($compareByte -ne $null) { "{0:X2}" -f $compareByte } else { "--" }
                    })
                }
            }

            $position += $maxRead

            $percentComplete = [math]::Round(($position / $totalLength) * 100, 2)
            Write-Progress -Activity "比较文件" -Status "$percentComplete% 完成" -PercentComplete $percentComplete
        }
    }
    finally {
        $sourceStream.Close()
        $compareStream.Close()
    }

    Write-Progress -Activity "比较文件" -Completed

    $sourceSizeFormatted = Format-FileSize -Size $sourceSize
    $compareSizeFormatted = Format-FileSize -Size $compareSize

    $summary = @"
源文件:$SourceFile
大小: $sourceSizeFormatted

比较文件:$CompareFile
大小: $compareSizeFormatted

不同之处: $($results.Count) 字节
详细如下:

"@

    $detailedOutput = "地址       源文件    比较文件`n"
    $detailedOutput += "--------------------------`n"
    $lastAddress = -1
    foreach ($result in $results) {
        if ($lastAddress -ne -1 -and $result.Address -ne $lastAddress + 1) {
            $detailedOutput += "`n"  # 添加空行表示不连续
        }
        $detailedOutput += "0x{0:X8}  {1}        {2}`n" -f $result.Address, $result.SourceFile, $result.CompareFile
        $lastAddress = $result.Address
    }

    $fullOutput = $summary + $detailedOutput

    if ($OutputFile) {
        $fullOutput | Out-File -FilePath $OutputFile -Encoding utf8
        Write-Host "结果已保存到: $OutputFile"
    }

    Write-Host $fullOutput
}

2、调用

        假设您将函数保存在名为 Compare-FileHex.ps1 的文件中。在您想要使用这个函数的其他 PowerShell 脚本中,您可以这样导入和使用它:

  1.  导入 Compare-FileHex 函数 . "C:\Path\To\Compare-FileHex.ps1"

  2.  现在您可以使用这个函数了 Compare-FileHex -SourceFile "path\to\source\file" -CompareFile "path\to\compare\file" -OutputFile "path\to\output.txt"

 3、效果 (gif 随便看了。渣画质)

分别采用两组参数 (不带生成txt与带生成txt的 f:\play.txt)
4、 生成的txt内容

源文件:D:\Program Files\Sublime Text\sublime_text.exe.old
大小: 7.74 MB

比较文件:D:\Program Files\Sublime Text\sublime_text.exe
大小: 7.74 MB

不同之处: 6 字节
详细如下:
地址       源文件    比较文件
--------------------------
0x0001A4E8  80        C6
0x0001A4E9  79        41

0x0001A4EB  00        01
0x0001A4EC  0F        B2
0x0001A4ED  94        00
0x0001A4EE  C2        90

5、结束语

        自用编制注册机时候的帮助工具,不用装什么软件工具。大文件,大差异没试验过,加了缓存参数,有兴趣自己试试吧,全源码公开。

---------------------------------------------------------------------------------------------------------------------------------

以下新版本(2024.10.21 )

1.进度条不再粗狂

2.差异过大就没意义比较了。(差异字节数 参数化 MaxDifferences 默认1000)

3.如有输出文件参数,输出文件自定加入时间戳,防止输出文件被覆盖

---------------------------------------------------------------------------------------------------------------------------------
 

function CompareFileHex {
    param (
        [Parameter(Mandatory=$true)]
        [string]$SourceFile,
        [Parameter(Mandatory=$true)]
        [string]$CompareFile,
        [Parameter(Mandatory=$false)]
        [string]$OutputFile,
        [Parameter(Mandatory=$false)]
        [int]$BufferSize = 1MB,
        [Parameter(Mandatory=$false)]
        [int]$MaxDifferences = 1000
       
    )

    function Format-FileSize {
        param ([long]$Size)
        if ($Size -ge 1GB) { "{0:N2} GB" -f ($Size / 1GB) }
        elseif ($Size -ge 1MB) { "{0:N2} MB" -f ($Size / 1MB) }
        elseif ($Size -ge 1KB) { "{0:N2} KB" -f ($Size / 1KB) }
        else { "$Size Bytes" }
    }

    # 检查文件是否存在
    if (-not (Test-Path $SourceFile)) {
        Write-Host "源文件 '$SourceFile' 不存在。请检查文件路径是否正确。"
        return
    }
    if (-not (Test-Path $CompareFile)) {
        Write-Host "比较文件 '$CompareFile' 不存在。请检查文件路径是否正确。"
        return
    }

    $sourceStream = [System.IO.File]::OpenRead($SourceFile)
    $compareStream = [System.IO.File]::OpenRead($CompareFile)
    $results = New-Object System.Collections.Generic.List[PSCustomObject]
    $buffer1 = New-Object byte[] $BufferSize
    $buffer2 = New-Object byte[] $BufferSize
    $totalLength = [Math]::Max($sourceStream.Length, $compareStream.Length)
    $position = 0
    $sourceSize = $sourceStream.Length
    $compareSize = $compareStream.Length
    $differenceCount = 0
  

    $Block = "█"
    $ProgressBarWidth = [Math]::Min([Console]::WindowWidth - 1, 50) # 使用控制台宽度或最大50个字符
    
    function Update-ProgressBar {
        param (
            [double]$PercentComplete
        )
        
        $filledWidth = [math]::Round($ProgressBarWidth * ($PercentComplete / 100))
        $progressBar = $Block * $filledWidth
    
        # 移动到第一行开始位置并更新进度文字
        [Console]::SetCursorPosition(0, [Console]::CursorTop - 1)
        Write-Host ("比较进度 {0:F2}%" -f $PercentComplete) -NoNewline
    
        # 移动到第二行开始位置并更新进度条
        [Console]::SetCursorPosition(0, [Console]::CursorTop + 1)
        Write-Host $progressBar.PadRight($ProgressBarWidth) -NoNewline -ForegroundColor DarkGreen
    }
    
    # 为进度条预留
    Write-Host "Code by:PeerLessSoul" -ForegroundColor Gray
    Write-Host " "
    
    try {
        while ($position -lt $totalLength -and $differenceCount -lt $MaxDifferences) {
            $read1 = $sourceStream.Read($buffer1, 0, $BufferSize)
            $read2 = $compareStream.Read($buffer2, 0, $BufferSize)
            $maxRead = [Math]::Max($read1, $read2)

            for ($i = 0; $i -lt $maxRead -and $differenceCount -lt $MaxDifferences; $i++) {
                $sourceByte = if ($i -lt $read1) { $buffer1[$i] } else { $null }
                $compareByte = if ($i -lt $read2) { $buffer2[$i] } else { $null }
                
                if ($sourceByte -ne $compareByte) {
                    $results.Add([PSCustomObject]@{
                        Address = $position + $i
                        SourceFile = if ($null -ne $sourceByte) { "{0:X2}" -f $sourceByte } else { "--" }
                        CompareFile = if ($null -ne $compareByte) { "{0:X2}" -f $compareByte } else { "--" }
                    })
                    $differenceCount++
                }
            }

            $position += $maxRead
            $percentComplete = [math]::Round(($position / $totalLength) * 100, 2)
             
            # 只在达到更新间隔时更新进度条
            Update-ProgressBar -PercentComplete $percentComplete
                
            
        }
    }
    finally {
        $sourceStream.Close()
        $compareStream.Close()
        Write-Host " " # 添加一个空行
    }

    #Write-Progress -Activity "比较文件" -Completed

    $sourceSizeFormatted = Format-FileSize -Size $sourceSize
    $compareSizeFormatted = Format-FileSize -Size $compareSize

    if ($differenceCount -ge $MaxDifferences) {
        $summary = @"
源文件:$SourceFile
大小: $sourceSizeFormatted
比较文件:$CompareFile
大小: $compareSizeFormatted
警告:差异数量过大(至少 $MaxDifferences 处),停止比较。
"@
        Write-Host $summary
        return
    }

    $summary = @"
源文件:$SourceFile
大小: $sourceSizeFormatted
比较文件:$CompareFile
大小: $compareSizeFormatted
不同之处: $($results.Count) 字节
详细如下:

"@ 

    $detailedOutput = "地址         源文件   比较文件`n"
    $detailedOutput += "--------------------------------`n"
    $lastAddress = -1
    foreach ($result in $results) {
        if ($lastAddress -ne -1 -and $result.Address -ne $lastAddress + 1) {
            $detailedOutput += "`n"  # 添加空行表示不连续
        }
        $detailedOutput += "0x{0:X8}   0x{1:X8}      0x{2:X8}`n" -f $result.Address, $result.SourceFile, $result.CompareFile
        $lastAddress = $result.Address
    }

    $fullOutput = $summary + $detailedOutput

    # 检查输出文件是否存在,并添加时间戳
    if ($OutputFile) {
        if (Test-Path $OutputFile) {
            $timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
            $baseName = [System.IO.Path]::GetFileNameWithoutExtension($OutputFile)
            $extension = [System.IO.Path]::GetExtension($OutputFile)
            $newOutputFile = [System.IO.Path]::Combine(
                [System.IO.Path]::GetDirectoryName($OutputFile),
                "$baseName`_$timestamp$extension"
            )
            $OutputFile = $newOutputFile
        }
        $fullOutput | Out-File -FilePath $OutputFile -Encoding utf8
        Write-Host "结果已保存到: $OutputFile"
    }

    Write-Host $fullOutput
}

效果:

2024.10.21 PS脚本 文件比较

视屏第一个命令执行文件差异过大,也就没必要比较了,直接终止比较

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值