![]() |
Erste Bytes einer Datei vergleichen?
Ich versuche, RAW-Dateien der diversen Kamerahersteller anhand ihrer Signaturen zu identifizieren. Hierbei gibt es die extrem nützliche Seite
![]() ![]() ![]() Zur einfachen Identifizierung von JPG-Dateien anhand der charakteristischen ersten beiden Bytes habe ich folgende Prozedur verwendet:
Delphi-Quellcode:
Jetzt sind die Signaturen der RAW-Dateien aber deutlich länger, die einer CRW-Datei von Canon lautet zum Beispiel
function JPGHeaderOK(const Dateiname:string):Boolean;
var Datei:File; Buf:TBytes; begin {$I-} Try Buf := [0,0]; Try AssignFile(Datei,Dateiname); Reset(Datei, 1); BlockRead(Datei, Buf[0], 2); Result := ((Buf[0] = $FF) and (Buf[1] = $D8)); Except Result := False; End; Finally CloseFile(Datei); SetLength(Buf,0); End; {$I+} end;
Delphi-Quellcode:
.
49 49 1A 00 00 00 48 45 41 50 43 43 44 52 02 00
Wie macht man das am besten? Der Einzelvergleich Buf[0]..Buf[15] kann es doch wohl kaum sein. |
AW: Erste Bytes einer Datei vergleichen?
Guten Abend,
darfst Du keine Exif-Bibliothek nutzen? Das Kamera-Model ist auch in den Exif-Daten vermerkt. Grüße Klaus |
AW: Erste Bytes einer Datei vergleichen?
|
AW: Erste Bytes einer Datei vergleichen?
Kaum fragt man, schon fallen einem die richtigen Suchbegriffe für Google ein.
Ein Machbarkeitskonzept auf der Basis einer Antwort auf ![]()
Delphi-Quellcode:
@Klaus01: Es ging um RAW-Dateien. Da gibt es kein normales EXIF und es hätte auch nichts genützt, da ich die Dateien ja anhand ihrer Signatur und nicht anhand ihrer Dateierweiterung identifizieren wollte.
function IstRAWFormat(const Dateiname:string):Boolean;
var Datei:File; Buf:array [0..19] of Byte; BufCRW:TBytes; //------------------------------------------------------------------------------------------------------------------------------------------ function ByteArrayPos(const SearchArr : array of byte; const CompArr : array of byte):integer; var Comp,Search : AnsiString; begin SetString(Comp, PAnsiChar(@CompArr[0]), Length(CompArr)); SetString(Search, PAnsiChar(@SearchArr[0]), Length(SearchArr)); Result := Pos(Search,Comp) - 1; end; //------------------------------------------------------------------------------------------------------------------------------------------ begin {$I-} Result := False; Try Try AssignFile(Datei,Dateiname); Reset(Datei, 1); BlockRead(Datei, Buf[0], 20); Except exit; End; BufCRW := [$49,$49,$1A,$00,$00,$00,$48,$45,$41,$50,$43,$43,$44,$52,$02,$00]; If ByteArrayPos(BufCRW,Buf) = 0 then Result := True; Finally CloseFile(Datei); SetLength(BufCRW,0); End; {$I+} end; @t.roller: Danke für den Hinweis! Die Liste erscheint aber nicht vollständig, so habe ich z.B. die ARW-Dateien von Sony nicht gefunden. |
AW: Erste Bytes einer Datei vergleichen?
|
AW: Erste Bytes einer Datei vergleichen?
Tja, hätte man darauf nicht selbst kommen können? Ehrlich gesagt, auf die Konstruktion mit
Delphi-Quellcode:
vermutlich nicht, obwohl sie mir geläufig ist. Also dann:
PAnsiChar(@BufCRW[0])
Delphi-Quellcode:
Übrigens, ist das
function IstRAWFormat(const Dateiname:string):Boolean;
var Datei:File; Buf:array [0..19] of Byte; BufCRW,BufARW,BufCR2:TBytes; begin {$I-} Try Try AssignFile(Datei,Dateiname); Reset(Datei, 1); BlockRead(Datei, Buf[0], 20); Except exit(False); End; BufCRW := [$49,$49,$1A,$00,$00,$00,$48,$45,$41,$50,$43,$43,$44,$52,$02,$00]; BufCR2 := [$49,$49,$2A,$00,$10,$00,$00,$00,$43,$52]; BufARW := [$49,$49,$2A,$00]; Result := CompareMem(PAnsiChar(@BufCRW[0]),PAnsiChar(@Buf[0]),Length(BufCRW)) or CompareMem(PAnsiChar(@BufCR2[0]),PAnsiChar(@Buf[0]),Length(BufCR2)) or CompareMem(PAnsiChar(@BufARW[0]),PAnsiChar(@Buf[0]),Length(BufARW)); Finally CloseFile(Datei); SetLength(BufCRW,0); SetLength(BufCR2,0); SetLength(BufARW,0); End; {$I+} end;
Delphi-Quellcode:
eigentlich nötig? (Auch das habe ich ziemlich oft gelesen, ich glaube daher, nicht).
SetLength(BufCRW,0);
|
AW: Erste Bytes einer Datei vergleichen?
Das ist genauso "nötig", wie das PAnsiChar(...) :angle2:
|
AW: Erste Bytes einer Datei vergleichen?
Wird ja immer kürzer.
Delphi-Quellcode:
Gibt es sonst noch was? Vielleicht die Steinzeitroutine
function IstRAWFormat(const Dateiname:string):Boolean;
var Datei:File; Buf:array [0..19] of Byte; BufCRW,BufARW,BufCR2,BufRW2,BufNEF,BufORF,BufPEF,BufRAF,BufRWL,BufSRW,BufX3F, BufERF,BufFFF,BufMEF,BufMRW,BufNRW,BufDCR,BufSRF:TBytes; begin Result := False; If FileExists(Dateiname) then begin AssignFile(Datei,Dateiname); {$I-} Reset(Datei, 1); BlockRead(Datei, Buf[0], 20); {$I+} If IOResult <> 0 then exit; BufCRW := [$49,$49,$1A,$00,$00,$00,$48,$45,$41,$50,$43,$43,$44,$52,$02,$00]; // Canon, veraltet BufCR2 := [$49,$49,$2A,$00,$10,$00,$00,$00,$43,$52]; // Canon BufARW := [$49,$49,$2A,$00]; // Sony, auch SR2 (Sony), 3FR (Hasselblad), IIQ (PhaseOne) BufRW2 := [$49,$49,$55,$00,$18,$00,$00,$00,$88,$E7,$74,$D8,$F8,$25,$1D,$4D]; // Panasonic BufNEF := [$4D,$4D,$00,$2A,$00,$00,$00,$08,$00]; // Nikon BufORF := [$49,$49,$52]; // Olympus BufPEF := [$4D,$4D,$00,$2A,$00]; // Pentax BufRAF := [$46,$55,$4A,$49,$46,$49,$4C,$4D,$43,$43,$44,$2D,$52,$41,$57,$20]; // Fujifilm BufRWL := [$49,$49,$55,$00]; // Leica BufSRW := [$4D,$4D,$00,$2A,$00,$00,$00,$08,$00,$06,$01,$0F,$00,$02,$00,$00]; // Samsung BufX3F := [$46,$4F,$56,$62]; // Sigma // veraltet BufDCR := [$44,$53,$43,$2D,$49,$6D,$61,$67,$65]; // Kodak, veraltet BufERF := [$43,$6F,$6D,$70,$75,$63,$6F,$6E,$20,$45,$4F,$53,$20,$44,$65,$73]; // Epson, veraltet BufFFF := [$4D,$4D,$00,$2A]; // Hasselblad, veraltet BufMEF := [$4D,$52,$00,$00,$00,$00,$00,$00,$00,$00,$1C,$0E]; // Mamiya, veraltet BufMRW := [$00,$4D,$52,$4D]; // Minolta, veraltet BufNRW := [$4E,$4F,$4B,$49,$41,$52,$41,$57]; // Nokia, veraltet BufSRF := [$4C,$53]; // Sony, veraltet, DSC-F828 von 2004 Result := CompareMem(@BufCRW[0],@Buf[0],Length(BufCRW)) or CompareMem(@BufCR2[0],@Buf[0],Length(BufCR2)) or CompareMem(@BufARW[0],@Buf[0],Length(BufARW)) or CompareMem(@BufRW2[0],@Buf[0],Length(BufRW2)) or CompareMem(@BufNEF[0],@Buf[0],Length(BufNEF)) or CompareMem(@BufORF[0],@Buf[0],Length(BufORF)) or CompareMem(@BufPEF[0],@Buf[0],Length(BufPEF)) or CompareMem(@BufRAF[0],@Buf[0],Length(BufRAF)) or CompareMem(@BufRWL[0],@Buf[0],Length(BufRWL)) or CompareMem(@BufSRW[0],@Buf[0],Length(BufSRW)) or CompareMem(@BufX3F[0],@Buf[0],Length(BufX3F)) // veraltet or CompareMem(@BufDCR[0],@Buf[0],Length(BufDCR)) or CompareMem(@BufERF[0],@Buf[0],Length(BufERF)) or CompareMem(@BufFFF[0],@Buf[0],Length(BufFFF)) or CompareMem(@BufMEF[0],@Buf[0],Length(BufMEF)) or CompareMem(@BufMRW[0],@Buf[0],Length(BufMRW)) or CompareMem(@BufNRW[0],@Buf[0],Length(BufNRW)) or CompareMem(@BufSRF[0],@Buf[0],Length(BufSRF)); CloseFile(Datei); end; end;
Delphi-Quellcode:
? Ich dachte, es ist ja nicht nötig, mit einem FileStream die ganze Datei einzulesen. Außerdem habe ich das
AssignFile
Delphi-Quellcode:
durch ein
Try..Except
Delphi-Quellcode:
ersetzt.
IOResult
|
AW: Erste Bytes einer Datei vergleichen?
Du denkst doch nicht etwa, dass man mit dem FileStream nur ganze Dateien einlesen kann?
Das ganze noch in eine Konstante oder Variable (Array of Array) und dann das Vergleichen in eine Schleife. TFileStream statt BlockRead nur ein Read und man braucht weder Try-Except noch IOResult. PS: Das AssignFile gehörte vor das erste Try. Da in Finally auf die Variable zugegriffen wird, gehört die Initialisierung vor das Try, damit es auch "immer" richtig initialisiert wird. Und durch das
Delphi-Quellcode:
war die Exceptionbehandluch sowieso falsch, da diese Dateifunktionen dort mit Fehlercodes (IOResult) und nicht mit Exceptions gearbeitet hatte.
{$I-}
|
AW: Erste Bytes einer Datei vergleichen?
Ich weiß zwar nicht, ob das für diesen Anwendungsfall relevant ist, aber ich baue sowas gerne hierarchisch auf:
Delphi-Quellcode:
Sinnvollerweise packt man das noch als statische Methoden in einen passenden Namespace (Record oder Klasse). Statt des Boolschen Results würde sich auch ein Aufzählungstyp für die verschiedenen Formate anbieten, falls man abhängig vom Format unterschiedlich reagieren möchte.
function IstRAWFormat(const Buf: TBytes):Boolean; overload;
const cRawHeader: TArray<TBytes> = [ [$49,$49,$1A,$00,$00,$00,$48,$45,$41,$50,$43,$43,$44,$52,$02,$00], // Canon, veraltet [$49,$49,$2A,$00,$10,$00,$00,$00,$43,$52], // Canon [$49,$49,$2A,$00], // Sony, auch SR2 (Sony), 3FR (Hasselblad), IIQ (PhaseOne) [$49,$49,$55,$00,$18,$00,$00,$00,$88,$E7,$74,$D8,$F8,$25,$1D,$4D], // Panasonic [$4D,$4D,$00,$2A,$00,$00,$00,$08,$00], // Nikon [$49,$49,$52], // Olympus [$4D,$4D,$00,$2A,$00], // Pentax [$46,$55,$4A,$49,$46,$49,$4C,$4D,$43,$43,$44,$2D,$52,$41,$57,$20], // Fujifilm [$49,$49,$55,$00], // Leica [$4D,$4D,$00,$2A,$00,$00,$00,$08,$00,$06,$01,$0F,$00,$02,$00,$00], // Samsung [$46,$4F,$56,$62], // Sigma // veraltet [$44,$53,$43,$2D,$49,$6D,$61,$67,$65], // Kodak, veraltet [$43,$6F,$6D,$70,$75,$63,$6F,$6E,$20,$45,$4F,$53,$20,$44,$65,$73], // Epson, veraltet [$4D,$4D,$00,$2A], // Hasselblad, veraltet [$4D,$52,$00,$00,$00,$00,$00,$00,$00,$00,$1C,$0E], // Mamiya, veraltet [$00,$4D,$52,$4D], // Minolta, veraltet [$4E,$4F,$4B,$49,$41,$52,$41,$57], // Nokia, veraltet [$4C,$53] // Sony, veraltet, DSC-F828 von 2004 ]; var rawHeader: TBytes; begin for rawHeader in cRawHeader do begin if CompareMem(@rawHeader[0], @Buf[0], Length(rawHeader)) then Exit(true); end; Result := false; end; function IstRAWFormat(Stream: TStream):Boolean; overload; var buf: TBytes; savePos: Int64; begin SetLength(buf, 20); savePos := Stream.Position; try Stream.ReadData(buf, Length(buf)); finally Stream.Position := savePos; end; Result := IstRAWFormat(buf); end; function IstRAWFormat(const Dateiname: string):Boolean; overload; var stream: TFileStream; begin stream := TFileStream.Create(Dateiname, fmOpenRead); try result := IstRAWFormat(stream); finally stream.Free; end; end; |
AW: Erste Bytes einer Datei vergleichen?
@Himitsu: Du hast natürlich Recht. Ich hatte den Code mal von irgendwoher übernommen und habe erst jetzt mal genauer geguckt:
Delphi-Quellcode:
und Try ist natürlich Unsinn. Hab ich ja auch geändert. TFileStream und Read ist auch besser.
$I-}
@Uwe Raabe: Wirklich toll. Was ich nicht verstehe: Warum das savePos? Aus Interesse: Wie sähe eine Enumeration denn aus? |
AW: Erste Bytes einer Datei vergleichen?
Zitat:
Zitat:
Delphi-Quellcode:
type
TRAWFormat = (rawUnknown, rawCanonOld, rawCanon, rawSony, rawPanasonic, rawNikon, rawOlympus, rawPentax, rawFuji, rawLeica, rawSamsung, rawSigma, rawKodak, rawEpson, rawHasselblad, rawMamiya, rawMinolta, rawNokia, rawSonyOld); function GetRAWFormat(const Buf: TBytes): TRAWFormat; overload; const cRawHeader: TArray<TBytes> = [ [$49,$49,$1A,$00,$00,$00,$48,$45,$41,$50,$43,$43,$44,$52,$02,$00], // Canon, veraltet [$49,$49,$2A,$00,$10,$00,$00,$00,$43,$52], // Canon [$49,$49,$2A,$00], // Sony, auch SR2 (Sony), 3FR (Hasselblad), IIQ (PhaseOne) [$49,$49,$55,$00,$18,$00,$00,$00,$88,$E7,$74,$D8,$F8,$25,$1D,$4D], // Panasonic [$4D,$4D,$00,$2A,$00,$00,$00,$08,$00], // Nikon [$49,$49,$52], // Olympus [$4D,$4D,$00,$2A,$00], // Pentax [$46,$55,$4A,$49,$46,$49,$4C,$4D,$43,$43,$44,$2D,$52,$41,$57,$20], // Fujifilm [$49,$49,$55,$00], // Leica [$4D,$4D,$00,$2A,$00,$00,$00,$08,$00,$06,$01,$0F,$00,$02,$00,$00], // Samsung [$46,$4F,$56,$62], // Sigma // veraltet [$44,$53,$43,$2D,$49,$6D,$61,$67,$65], // Kodak, veraltet [$43,$6F,$6D,$70,$75,$63,$6F,$6E,$20,$45,$4F,$53,$20,$44,$65,$73], // Epson, veraltet [$4D,$4D,$00,$2A], // Hasselblad, veraltet [$4D,$52,$00,$00,$00,$00,$00,$00,$00,$00,$1C,$0E], // Mamiya, veraltet [$00,$4D,$52,$4D], // Minolta, veraltet [$4E,$4F,$4B,$49,$41,$52,$41,$57], // Nokia, veraltet [$4C,$53] // Sony, veraltet, DSC-F828 von 2004 ]; var I: Integer; rawHeader: TBytes; begin for I := Low(rawHeader) to High(rawHeader) do begin rawHeader := cRawHeader[I]; if CompareMem(@rawHeader[0], @Buf[0], Length(rawHeader)) then Exit(TRawFormat(I)); end; Result := rawUnknown; end; |
AW: Erste Bytes einer Datei vergleichen?
Das SavePos ist, damit die Funktion univeral ist und den Stream nicht verändert, für nachfolgene Leseoperationen.
Delphi-Quellcode:
und man kann erstens direkt Result als Schleifenvariable nutzen und hat eine Bereichsprüfung für das Array, damit die Anzahl mit dem Enum übereinstimmt.
array[TRAWFormat] of TBytes
|
AW: Erste Bytes einer Datei vergleichen?
Zitat:
|
AW: Erste Bytes einer Datei vergleichen?
Vielen Dank euch beiden.
Delphi-Quellcode:
war der Punkt. Dass man an den (Integer-)Wert mittels
TRawFormat(I)
Delphi-Quellcode:
rankommt, weiß ich mittlerweile; dass man auf ein Glied von TRawFormat so einfach zugreifen kann, weiß ich jetzt.
Ord(RawFormat)
Das savePos war mir nicht klar, weil ich ja gerade eben von jeder JPG-Datei nur die ersten 20 Bytes auslesen will; aber klar, für einen universelleren Gebrauch ist das nützlich. Ebenfalls aus (Fortbildungs-)Interesse: Ist es vielleicht eine Illusion zu glauben, man würde mit einer Beschränkung auf die ersten 20 Bytes Zeit sparen? Wäre es bei einer Festplatte schneller, einen Sektor auszulesen? Oder ist das egal, weil sowieso immer ein Sektor ausgelesen wird? Werden bei einer SSD hingegen tatsächlich nur die ersten 20 Bytes gelesen? |
AW: Erste Bytes einer Datei vergleichen?
Üblicherweise wird eine ganze Zuordnungseinheit gelesen.
Die ist formatabhängig und abhängig von der Grösse des Speichermediums. Beispiel USB-Stick 8 GB Zuordnungseinheit: FAT32: 4096 Bytes NTFS: 4096 Bytes exFAT: 32 KBytes |
AW: Erste Bytes einer Datei vergleichen?
Die von dir genutzen File-APIs verwenden alle den WindowsFileCache.
Somit ist es egal ob 1, 20 oder 200 Byte gelesen werden. Die Festplatte liefert eh immer nur ganze Sektoren, wodurch also immer mindestens ein Sektor ausgelesen wird. |
AW: Erste Bytes einer Datei vergleichen?
Hab ich mir so ungefähr gedacht. Laut einer Quelle verwendet der File Cache immer "Sections" von 256 KB, das wäre also noch deutlich mehr als ein Festplattensektor. Merk ich mir mal für die Zukunft, dass man eine Datei immer 256 KB weit auslesen kann, wenn man sie überhaupt anfasst.
|
AW: Erste Bytes einer Datei vergleichen?
Ich hatte bei der WFC mindestens 4K erwartet, da Windows den Arbeistspeicher in 4K-Blöcken verwaltet. :angle:
Aber vom Tempo her ist das da fast egal ob ein Vierttel oder Vier. Zitat:
Die kleinste Sektorgröße ist 512. (bei den meisten HDDs) Bei großen Terrabyteplatten sind die Sektoren auch schon mal 4K oder mehr. Bei SSDs sind die realen Speicherblöcke oft sogar mehrere Sektoren groß, da die sich kompatibel ausgeben wollen (512 vorgaukeln, aber eigentlich mehrere Sektoren in einem Speicherbereich liegen haben) Und in Windows und Co. sind die Clustergrößen oft auch nochmal größer als je ein Sektor, vorallem bei sehr großen Partitionen. (siehe Datenträgerformatierung) |
AW: Erste Bytes einer Datei vergleichen?
Zitat:
Zitat:
|
AW: Erste Bytes einer Datei vergleichen?
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
"As depicted by the solid arrows in the previous figure, a 256 KB region of data is read into a 256 KB cache "slot" in system address space when it is first requested by the cache manager during a file read operation." ![]() |
AW: Erste Bytes einer Datei vergleichen?
![]() Zitat:
|
AW: Erste Bytes einer Datei vergleichen?
Der obige Link ist nicht mehr gültig.
![]() Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:02 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz