一上来就放代码(下面已更新)
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 脚本中,您可以这样导入和使用它:
-
导入 Compare-FileHex 函数 . "C:\Path\To\Compare-FileHex.ps1"
-
现在您可以使用这个函数了 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脚本 文件比较
视屏第一个命令执行文件差异过大,也就没必要比较了,直接终止比较