我需要一个脚本来读取输入文件并计算每个 9728000 字节块的 MD4 校验和,直到文件结束。我之前曾这样做过,首先将所有 9728000 字节块提取为单个文件,然后使用名为的命令行工具计算每个文件的 MD4 校验和总和,但这并不方便,尤其是对于大文件而言。
据我所知,PowerShell 可以本机计算 MD5 校验和,但不能计算 MD4。
我使用以下脚本进行了测试,该脚本改编自获得的代码那里,但我还是不完全理解。
$input = Read-Host "File name"
$file = Get-Item -LiteralPath $input
$offset = 0
$length = $file.length
$name = $file.name
$hasher = [System.Security.Cryptography.HashAlgorithm]::Create('MD5')
for ($offset -lt $length) {
$buffer = [Byte[]]::new(9728000)
$stream = [System.IO.FileStream]::new($file.FullName, 'Open', 'Read')
$stream.Position = $offset
$readSize = $stream.Read($buffer, 0, 9728000)
$md5 = $hasher.ComputeHash($buffer, 0, $readSize)
$stream.Dispose()
echo "$md5 $offset" >> "$name MD5.txt"
$offset = $offset + 9728000
}
结果如下:
78 224 90 67 158 49 86 127 118 179 251 89 133 103 144 25 0
190 40 170 149 51 93 153 191 212 194 162 165 38 124 57 96 9728000
160 20 197 150 189 246 209 156 212 84 154 21 200 7 148 228 19456000
...
但是 1) 这不是我需要的布局,2) 我特别需要 MD4,3) 另一个问题是,尽管有条件,但即使没有更多数据可读取,循环也不会停止$offset -lt $length
(我一定是做错了)。
我需要的是常规的 32 字节 MD4 字符串:
908CB75033311ADCB0FBCD0DCD869050 0
A1211C1B77C0EFFA98DB8F719AB30A93 9728000
D9719A4CB32F2D350CB39A0CB790424B 19456000
...
然后今天我发现这个 MD4 脚本。我尝试通过修改上述脚本来使用它,但是失败了,misebarly。此外,如果我将脚本的全部内容(以 开头function Get-MD4...
)复制到我自己的脚本中,该函数也无法被识别,只有通过“点源”调用脚本时它才有效(这是我在花了大约 2 个小时研究这个概念的过程中发现的一个概念,我查阅了几本 400 多页的 PowerShell PDF 书,但除此之外几乎没有帮助)。这可能是由于格式问题造成的吗?(如果我在 Notepad2 中打开 md4.ps1 脚本,它会显示行尾是“LF”,而我的脚本有“CR+LF”行尾。这不是主要问题,但它今天下午真的让我很恼火,所以我想知道发生了什么。)
这自述文件因为该脚本包含以下内容:
This is a MD4 algorithm function wrote in powershell. PS> Get-MD4 -String 'abc' -UpperCase A448017AAF21D8525FC10AE87AA6729D PS> $b = @('abc'.ToCharArray() | %{[int]$_}) PS> Get-MD4 -bArray $b a448017aaf21d8525fc10ae87aa6729d
我不明白开头的那行$b =
,也不知道如何在这些 PDF 书籍或网络搜索中找到相关内容。所以我再次不知所措。
一次读取一个大小定义的块的文件,将其作为函数的输入Get-MD4
,然后增加 $offset 值,依此类推,直到文件末尾,最有效的方法是什么?我应该使用-String
还是-bArray
?
如果这很重要的话,目标是检查在 eDonkey 网络上共享但 ED2K 校验和不匹配的文件。例如,我有一个 4GB 的 MKV 文件,使用 eMule 搜索时,我发现一个大小完全相同但 ED2K 校验和不同的 MKV 文件,因此我想知道哪些特定部分不同(ED2K 校验和是每个 9728000 字节块的 MD4 字符串列表的 MD4 校验和,可以在元数据文件中找到),然后我可以专门下载这些部分,以检查该文件的损坏版本是我拥有的还是当前共享的。希望这很清楚。否则,没关系,让我们专注于手头的主题“计算部分 MD4 校验和”。
答案1
上述代码效率极低,因为每次循环迭代都会创建一个新的大缓冲区和一个新的流。溪流已经为您处理了偏移量和所有内容,因此循环体实际上非常简单:
Param (
[parameter(Mandatory)][string]$InputFile,
[int]$ChunkSize = 9728000
)
. .\md4.ps1
# Or copy the md4.ps1 content here, or add to the $PROFILE
class Md4Info {
[string]$Checksum
[int]$Offset
}
$stream = [IO.FileStream]::new($InputFile, [IO.FileMode]::Open, [IO.FileAccess]::Read)
$buffer = [Byte[]]::new($ChunkSize)
while (($readSize = $stream.Read($buffer, 0, $ChunkSize)) -gt 0) {
[Md4Info]@{
Checksum = Get-MD4 -bArray $buffer[0..$readSize]
Offset = $stream.Position
}
}
$stream.Dispose()
这比你的代码有了很大的改进,但显然它不是最有效的方法因为MD4.PS1上面的脚本是为非常老的 PowerShell 版本编写的,效率极低。它还会错误地处理 Unicode,因此使用-String
可能会返回损坏的输出。无论如何,您可以通过将我上面的更新代码保存为 *.ps1 文件(例如)来尝试Get-ChunkMd4.ps1
。示例输出:
PS D:\test> .\Get-ChunkMd4.ps1 D:\test\file.txt
Checksum Offset
-------- ------
11cf3ecf1a3a9d1b270c9e313901441d 0
PS D:\test> .\Get-ChunkMd4.ps1 D:\test\file.mp4 -ChunkSize 1MB
Checksum Offset
-------- ------
8932ec620ef5df53f519e6271931bc0d 0
92a8f97be075655bfd1e8670368ff2a3 1048576
c6ec8e0d67b42cc3a9a1bc9d5c9fa8f0 2097152
1339bac99b94397b5848d1d86b0cc49e 3145728
fd643f329daeb73e07e24194fd1b0a31 4194304
话虽如此,你永远不可能拥有最多除非你使用硬件加速和/或 SIMD 编写一些高效的并行代码并编译为本机代码,否则这种方法是行不通的。本机 MD4 库的运行速度可能比上面的脚本快数千倍或数百万倍。事实上,使用 AVX-512 的良好哈希库可以达到3-30 GB/秒甚至更多,但md4.ps1
它的表现非常糟糕,在我的机器(Ryzen 5 4600H)上,仅仅哈希一个 8.2 MB 的小文件就需要 4 分钟,这是~29.5 KB/s!!!放心吧,你下载视频文件时甚至无法快速哈希它们。你应该找到一个这样的第三方库/工具,并使用上面的循环向它们提供数据
另请注意,如果您经常使用某个功能,那么您应该将其添加到配置文件中,如下所示
Add-Content -Path $profile -Value ". .\md4.ps1"
现在,您只需删除. .\md4.ps1
脚本中的该函数即可,因为每次运行 PowerShell 时都会加载该函数