
Ich brauche ein Skript, das eine Eingabedatei liest und MD4-Prüfsummen für jeden 9728000-Byte-Block bis zum Ende der Datei berechnet. Ich habe das schon einmal gemacht, indem ich zuerst alle 9728000-Byte-Blöcke als einzelne Dateien extrahiert und dann die MD4-Prüfsumme für jeden Block mit einem Befehlszeilentool namensfsum, aber das ist insbesondere bei großen Dateien nicht praktisch.
Soweit ich weiß, kann PowerShell MD5-Prüfsummen nativ berechnen, MD4 jedoch nicht.
Ich habe Tests mit dem folgenden Skript durchgeführt, das aus erhaltenem Code angepasst wurdeDort, und die ich immer noch nicht ganz verstehe.
$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
}
Die Ergebnisse waren wie folgt:
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
...
Aber 1) ist dies nicht das Layout, das ich brauche, 2) ich brauche speziell MD4 und 3) ein weiteres Problem besteht darin, dass die Schleife trotz der Bedingung nicht stoppt, selbst wenn keine Daten mehr zu lesen sind $offset -lt $length
(ich muss es falsch machen).
Was ich brauche, sind normale 32-Byte-MD4-Strings:
908CB75033311ADCB0FBCD0DCD869050 0
A1211C1B77C0EFFA98DB8F719AB30A93 9728000
D9719A4CB32F2D350CB39A0CB790424B 19456000
...
Dann fand ich heutedieses MD4-Skript. Ich habe versucht, es zu verwenden, indem ich das obige Skript angepasst habe, aberkläglich gescheitert. Außerdem wurde die Funktion nicht erkannt, wenn ich den gesamten Inhalt des Skripts (beginnend mit function Get-MD4...
) in mein eigenes Skript kopierte. Sie funktioniert nur, wenn ich das Skript über „Dot-Sourcing“ aufrufe (ein Konzept, das ich nebenbei entdeckte, als ich etwa 2 Stunden damit verbrachte und mehrere über 400 Seiten lange PDF-Bücher zu PowerShell durchforstete, die ansonsten kaum weiterhalfen). Könnte es an einem Formatierungsproblem liegen? (Wenn ich das Skript md4.ps1 in Notepad2 öffne, heißt es, dass die Zeilenenden „LF“ sind, während mein Skript Zeilenenden mit „CR+LF“ hat. Das ist nicht das Hauptproblem, aber es hat mich heute Nachmittag wirklich geärgert, also würde ich gerne wissen, was los war.)
DerREADME-Dateidenn das Skript enthält Folgendes:
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
Ich verstehe die Zeile nicht, die mit beginnt $b =
, und ich habe keine Ahnung, wie ich in diesen PDF-Büchern oder bei einer Websuche etwas Relevantes finden könnte. Also bin ich wieder einmal ratlos.
Was wäre die effizienteste Methode, eine Datei Stück für Stück in definierter Größe zu lesen, diese als Eingabe für die Get-MD4
Funktion zu verwenden und dann den Wert für $offset zu erhöhen usw., bis zum Ende der Datei? Soll ich -String
oder verwenden -bArray
?
Das Ziel, falls das wichtig ist, ist es, Dateien zu prüfen, die im eDonkey-Netzwerk freigegeben sind, aber eine nicht übereinstimmende ED2K-Prüfsumme aufweisen. Ich habe beispielsweise eine 4 GB große MKV-Datei. Bei einer Suche mit eMule habe ich eine MKV-Datei mit genau derselben Größe, aber einer anderen ED2K-Prüfsumme gefunden. Ich möchte also wissen, welche spezifischen Teile unterschiedlich sind (die ED2K-Prüfsumme ist die MD4-Prüfsumme der Liste der MD4-Zeichenfolgen für jeden 9728000-Byte-Block, die in der Metadatendatei zu finden ist). Dann kann ich gezielt diese Teile herunterladen, um zu prüfen, ob die beschädigte Version dieser Datei die ist, die ich habe, oder die, die derzeit freigegeben ist. Ich hoffe, das ist klar. Ansonsten, egal, konzentrieren wir uns auf das eigentliche Thema, nämlich „Berechnen partieller MD4-Prüfsummen“.
Antwort1
Der obige Code ist höchst ineffizient, da bei jeder Schleifeniteration ein neuer riesiger Puffer und ein neuer Stream erstellt werden.Stromverarbeitet bereits Offsets und alles andere für Sie, sodass der Schleifenkörper eigentlich sehr einfach ist:
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()
Das ist eine enorme Verbesserung gegenüber Ihrem Code, aber offensichtlich ist es nicht dieder effizienteste Wegweil dasmd4.ps1Das obige Skript wurde für eine sehr alte PowerShell-Version geschrieben und ist äußerst ineffizient. Es verarbeitet Unicode auch falsch, sodass die Verwendung -String
möglicherweise eine beschädigte Ausgabe zurückgibt. Sie können es trotzdem versuchen, indem Sie meinen aktualisierten Code oben als *.ps1-Datei speichern, z. B. Get-ChunkMd4.ps1
. Beispielausgabe:
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
Das heißt, man kann nie dieam meisteneffiziente Art und Weise, es sei denn, Sie schreiben hocheffizienten parallelen Code mit Hardwarebeschleunigung und/oder SIMD und kompilieren ihn in nativen Code. Eine native MD4-Bibliothek kann tausende oder Millionen Mal schneller laufen als das obige Skript. Tatsächlich kann eine gute Hashing-Bibliothek mit AVX-512 hashen bei3 bis 30 GB/soder mehr, aber es md4.ps1
ist so schlimm, dass es 4 Minuten braucht, nur um eine winzige 8,2 MB große Datei auf meinem Rechner (Ryzen 5 4600H) zu hashen, was~29,5 KB/s!!!Seien Sie versichert, dass Sie die Videodatei beim Herunterladen nicht schnell genug hashen können. Sie sollten wirklich eine solche Drittanbieterbibliothek/ein solches Drittanbietertool finden und diese mit der obigen Schleife mit Daten füttern.
Beachten Sie auch: Wenn Sie eine Funktion häufig verwenden, sollten Sie sie wie folgt zum Profil hinzufügen
Add-Content -Path $profile -Value ". .\md4.ps1"
Jetzt können Sie einfach das . .\md4.ps1
in Ihrem Skript entfernen, da die Funktion jedes Mal geladen wird, wenn PowerShell ausgeführt wird