![]() |
Datei auf Indikatoren für Binärdatei testen?
Hallo!
Ich möchte testen, ob eine Datei eine "Binärdatei" oder eine "Textdatei" ist. (Ich bin mir der Problematik dieser Unterscheidung bewusst). Dazu teste ich, ob in den ersten n Bytes dieser Datei Indikatoren für eine Binärdatei enthalten sind: EDIT 10.5.2015: Besser wäre diese Formulierung: Ich möchte testen, ob eine Datei keine "Binärdatei" ist (d.h. mit möglichst hoher Wahrscheinlichkeit bei vertretbarem Aufwand ausschließen, dass es eine Binärdatei ist). Deswegen wäre ein besserer Name für die Funktion: IsNotBinaryFile. Aber das würde ggf. zu einer doppelten Verneinung im Code führen ("if not IsNotBinaryFile"), was wiederum unnötig umständlich wäre; deshalb belasse ich es bei "IsTextFile".
Delphi-Quellcode:
Welche anderen Indikatoren könnte man verwenden?
function IsTextFile(const AFile: string; const ABytesCount: Integer = 1000): Boolean;
// testet, ob die ersten ABytesCount Bytes einer Datei Indikatoren für eine Binär-Datei enthalten: // wenn nicht, muss es wohl eine Textdatei sein? // Siehe auch: http://qc.embarcadero.com/wc/qcmain.aspx?d=84071 var Reader: TStreamReader; Ch: AnsiChar; c: Integer; begin Result := True; c := 0; Reader := TStreamReader.Create(TFileStream.Create(AFile, fmOpenRead), TEncoding.ANSI); try if Reader.EndOfStream then begin CodeSite.Send('Nothing to read'); Result := False; EXIT; end; while Reader.Peek() >= 0 do begin Ch := AnsiChar(Reader.Read()); if Ch = #0 then begin CodeSite.Send('Null Byte found'); Result := False; EXIT; end; // Todo: andere Indikatoren? Inc(c); if c > ABytesCount then EXIT; end; finally CodeSite.Send('Bytes read', c); Reader.Close(); Reader.BaseStream.Free; Reader.Free(); end; end; procedure TForm1.btnTestClick(Sender: TObject); var d: Int64; begin d := GetTickCount; CodeSite.Send('Is Text File?', IsTextFile(edt1.Text)); CodeSite.Send('Duration', GetTickCount - d); end; |
AW: Datei auf Indikatoren für Binärdatei testen?
Es kommt darauf an, was das für dine "Text"-Datei sein soll und vorallem in welchem Format.
Bei sowas wie UFT-8 kann man prüfen, ob es ungültige UTF-8-Sequenzen enthält und wenn ja, dann ist es kein UTF-8. Von den ersten 32 "Control"-Zeichen (ASCII) werden im "Allgemeinen" nur 2 bis 3 verwendet (Tab und Zeilenumbruch) und ansonsten sollte man oftmals nichts finden. |
AW: Datei auf Indikatoren für Binärdatei testen?
Und ein Null-Byte ist kein Indikator. In UTF-16 Codiert gespeicherten Dateien wirst du sehr viele 0er Byte finden. So wäre das $-Zeichen als 00 24 in der Datei vorhanden.
Für mich wäre zwei Null-Bytes hintereinander ein Indikator. Oder das Prüfen auf die Bekannten Magic Bytes. In Wikipedia ( ![]() |
AW: Datei auf Indikatoren für Binärdatei testen?
Im Prinzip wären das 2 Ansätze:
1. Der Scan-Ansatz kann leicht in Arbeit ausarten, wenn man viele Kodierungen unterstützen will. Außerdem muss man sich genau überlegen, welche Zeichen man verbieten möchte und welche vielleicht doch im Text vorkommen können. Wenn man nur auf Nullbytes testen möchte, kann man sich den größten Teil der Arbeit bei der Dekodierung vermutlich sparen. 2. Das Testen auf die Magic-Bytes ist auf jeden Fall interessant, da es quasi nichts kostet. Man sollte aber beachten, das einige Magic-Bytes valider Text sind und auch am Anfang von Textdokumenten vorkommen könnten. |
AW: Datei auf Indikatoren für Binärdatei testen?
Ich habe die Funktion jetzt erweitert:
1. Testen auf Doppel-NullBytes anstatt auf einfache NullBytes 2. Testen auf mehr als n verbotene ControlBytes
Delphi-Quellcode:
function IsTextFile(const AFile: string; const ABytesCount: Integer = 1000): Boolean;
// testet, ob die ersten ABytesCount Bytes einer Datei Indikatoren für eine Binär-Datei enthalten: // wenn nicht, muss es wohl eine Textdatei sein? // Siehe auch: http://qc.embarcadero.com/wc/qcmain.aspx?d=84071 const MaxAllowedForbiddenControlCharsCount = 1; var Reader: TStreamReader; Ch: AnsiChar; c: Integer; PreviousCharWasNullByte: Boolean; ForbiddenControlCharsCount: Integer; begin Result := True; c := 0; PreviousCharWasNullByte := False; ForbiddenControlCharsCount := 0; Reader := TStreamReader.Create(TFileStream.Create(AFile, fmOpenRead), TEncoding.ANSI); try if Reader.EndOfStream then begin CodeSite.Send('Nothing to read'); Result := False; EXIT; end; while Reader.Peek() >= 0 do begin Ch := AnsiChar(Reader.Read()); if Ch = #0 then begin if PreviousCharWasNullByte then begin CodeSite.Send('Double Null Byte found'); Result := False; EXIT; end; PreviousCharWasNullByte := True; end else begin PreviousCharWasNullByte := False; if Ch in [#1..#8, #14..#31] then begin Inc(ForbiddenControlCharsCount); CodeSite.Send('This forbidden control char', HexDisplayPrefix + IntToHex(Ord(Ch), 2)); end; if ForbiddenControlCharsCount > MaxAllowedForbiddenControlCharsCount then begin CodeSite.Send('More than ' + IntToStr(MaxAllowedForbiddenControlCharsCount) + ' forbidden control chars found'); Result := False; EXIT; end; end; // Todo: andere Indikatoren? Inc(c); if c > ABytesCount then EXIT; end; finally CodeSite.Send('Bytes read', c); Reader.Close(); Reader.BaseStream.Free; Reader.Free(); end; end; procedure TForm1.btnTestClick(Sender: TObject); var d: Int64; begin d := GetTickCount; CodeSite.Send('Is Text File?', IsTextFile(edt1.Text)); CodeSite.Send('Duration', GetTickCount - d); end; |
AW: Datei auf Indikatoren für Binärdatei testen?
Gibt es Anzeichen für BOM? Wenn ja, versuche, die nächsten paar Bytes entsprechend zu interpretieren.
Wenn nicht, kann es a) eine Unicode-Datei ohne BOM b) eine ASCII-Datei c) eine Binärdatei sein Bei (a) ist jedes zweite Byte eine 0. Vermutlich. Bei (b) sind die Bytes=9,10,30 oder >=32 und <= 127. Meistens. Du erstellst also eine Häufigkeitstabelle der ersten paar Zeichen (N=20 z.B.) Bestehen die Bytes nur aus Zeichen, Ziffer, CR/LF? Dann handelt es sich vermutlich um eine Textdatei. Haben wir fast so viele Nullen wie sonstige Bytes und sind die Bytes auch Zeichen, Ziffer CR/LF? Dann ist es vermutlich eine Unicode-Datei Ansonsten ist die Wahrscheinlichkeit groß, das es sich um eine Binär bzw. um keine Textdatei handelt. Aber sicher kannst Du nicht immer sein. |
AW: Datei auf Indikatoren für Binärdatei testen?
Zitat:
|
AW: Datei auf Indikatoren für Binärdatei testen?
Zitat:
![]() Zitat:
|
AW: Datei auf Indikatoren für Binärdatei testen?
Kann man davon ausgehen, dass UTF-16- und UTF-32-Dateien statistisch signifikant so gut wie immer einen BOM enthalten?
|
AW: Datei auf Indikatoren für Binärdatei testen?
Wieso findest Du meine Heuristik denn unsicher? Wie willst du denn sonst Text-Dateien von irgendwelchen anderen Dateien unterscheiden? Genau genommen müsstest Du auch noch prüfen, ob die Datei Wörter enthält, oder zählst Du eine Base-64 Codierung auch zu Textdateien? Also, 'FXYyya678pphr'.. ist das jetzt eine Textdatei?
Und die paar Bytes an BOM können ja auch in jeder Binärdatei am Anfang stehen, ergo solltest du noch die nächsten paar Bytes analysieren. Meinst du nicht auch? |
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:17 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