使用PowerShell在二进制文件中查找和替换十六进制值



更新:我有一个工作脚本来完成任务。我需要批处理一堆文件,因此它接受了一个格式为文件名,OriginalHex,correctedHex的CSV文件。即使将搜索限制在第一个512字节之后,它也非常慢。它可能会写得更好,更快。感谢您的帮助。

更新2:修改搜索方法要更快,但远远不如专用的十六进制编辑器快。请注意,这是记忆密集型的。在RAM中的文件大小约为32倍。10MB = 320MB RAM。100MB = 3.2GB的RAM。我不建议大文件。它还保存到新文件而不是覆盖。原始文件重命名为file.ext_original@date time。

Import-CSV $PSScriptRootHEXCorrection.csv | ForEach-Object {
  $File = $_.'FileName'
  $Find = $_.'OriginalHEX'
  $Replace = $_.'CorrectedHEX'

  IF (([System.IO.File]::Exists("$PSScriptRoot$File"))) {
    $Target = (Get-ChildItem -Path $PSScriptRoot$File)
  } ELSE {
    Write-Host $File "- File Not Found`n" -ForegroundColor 'Red'
    RETURN
  }
  Write-Host "File:   "$Target.Name`n"Find:    "$Find`n"Replace: "$Replace
  $TargetLWT = $Target.LastWriteTime
  $TargetCT = $Target.CreationTime
  IF ($Target.IsReadOnly) {
    Write-Host $Target.Name "- Is Read-Only`n" -ForegroundColor 'Red'
    RETURN
  }
  $FindLen = $Find.Length
  $ReplaceLen = $Replace.Length
  $TargetLen = (1..$Target.Length)
  IF (!($FindLen %2 -eq 0) -OR !($ReplaceLen %2 -eq 0) -OR 
  [String]::IsNullOrEmpty($FindLen) -OR [String]::IsNullOrEmpty($ReplaceLen)) {
    Write-Host "Input hex values are not even or empty" -ForegroundColor 'DarkRed'
    RETURN
  } ELSEIF (
    $FindLen -ne $ReplaceLen) {
    Write-Host "Input hex values are different lengths" -ForegroundColor 'DarkYellow'
    RETURN
  }
  $FindAsBytes = New-Object System.Collections.ArrayList
  $Find -split '(.{2})' | ? {$_} | % { $FindAsBytes += [Convert]::ToInt64($_,16) }
  $ReplaceAsBytes = New-Object System.Collections.ArrayList
  $Replace -split '(.{2})' | ? {$_} | % { $ReplaceAsBytes += [Convert]::ToInt64($_,16) }
  # ^-- convert to base 10
  Write-Host "Starting Search"
  $FileBytes = [IO.File]::ReadAllBytes($Target)
  FOREACH ($Byte in $FileBytes) {
        $ByteCounter++
        IF ($Byte -eq [INT64]$FindAsBytes[0]) { TRY {
             (1..([INT64]$FindAsBytes.Count-1)) | % {
               $Test = ($FileBytes[[INT64]$ByteCounter-1+[INT64]$_] -eq $FindAsBytes[$_])
               IF ($Test -ne 'True') {
                 THROW
               }
  }
    Write-Host "Found at Byte:" $ByteCounter -ForegroundColor 'Green'
    (0..($ReplaceAsBytes.Count-1)) | % {
      $FileBytes[[INT64]$ByteCounter+[INT64]$_-1] = $ReplaceAsBytes[$_]}
  $Found = 'True'
  $BytesReplaces = $BytesReplaces + [INT64]$ReplaceAsBytes.Count
  }
CATCH {}
}
}
  IF ($Found -eq 'True'){
    [IO.File]::WriteAllBytes("$Target-temp", $FileBytes)
    $OriginalName = $Target.Name+'_Original'+'@'+(Get-Date).ToString('yyMMdd-HHmmss')
    Rename-Item -LiteralPath $Target.FullName -NewName $OriginalName
    Rename-Item $Target"-temp" -NewName $Target.Name
    #Preserve Last Modified Time
    $Target.LastWriteTime = $TargetLWT
    $Target.CreationTime = $TargetCT
    Write-Host $BytesReplaces "Bytes Replaced" -ForegroundColor 'Green'
    Write-Host "Original saved as:" $OriginalName
  } ELSE {
      Write-Host "No Matches" -ForegroundColor 'Red'}
    Write-Host "Finished Search`n"
    Remove-Variable -Name * -ErrorAction SilentlyContinue
} # end foreach from line 1
PAUSE

原始:以前曾提出过要求,但没有找到解决方案来执行简单直接的发现值并替换大型文件100MB 上的十六进制值。最好是针对此任务的命令行支持的十六进制编辑器的任何建议。

这是第一个裂缝:

(get-content -encoding byte file) -replace 'b10b',11 -as 'byte[]'

我正在检查其他链接,但是搜索和替换的唯一答案是一些错误。我投票重新开放。Mklement0一个人很近。他们都没有搜索,然后打印替换的位置。

没关系。您的速度更快,使用较少的内存。

最新更新