AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein Delphi Datei auf Indikatoren für Binärdatei testen?
Thema durchsuchen
Ansicht
Themen-Optionen

Datei auf Indikatoren für Binärdatei testen?

Ein Thema von PeterPanino · begonnen am 9. Mai 2015 · letzter Beitrag vom 13. Mai 2015
Antwort Antwort
Seite 1 von 5  1 23     Letzte »    
PeterPanino

Registriert seit: 4. Sep 2004
1.465 Beiträge
 
Delphi 10.4 Sydney
 
#1

Datei auf Indikatoren für Binärdatei testen?

  Alt 9. Mai 2015, 02:54
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:
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;
Welche anderen Indikatoren könnte man verwenden?

Geändert von PeterPanino (10. Mai 2015 um 00:29 Uhr) Grund: Hinzufügung einer genaueren Formulierung der Frage
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#2

AW: Datei auf Indikatoren für Binärdatei testen?

  Alt 9. Mai 2015, 07:27
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.
$2B or not $2B
  Mit Zitat antworten Zitat
Benutzerbild von Bernhard Geyer
Bernhard Geyer

Registriert seit: 13. Aug 2002
17.202 Beiträge
 
Delphi 10.4 Sydney
 
#3

AW: Datei auf Indikatoren für Binärdatei testen?

  Alt 9. Mai 2015, 09:05
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 (http://en.wikipedia.org/wiki/List_of_file_signatures) gibts hierfür eine kleine Liste
Windows Vista - Eine neue Erfahrung in Fehlern.
  Mit Zitat antworten Zitat
Benutzerbild von BUG
BUG

Registriert seit: 4. Dez 2003
Ort: Cottbus
2.094 Beiträge
 
#4

AW: Datei auf Indikatoren für Binärdatei testen?

  Alt 9. Mai 2015, 10:39
Im Prinzip wären das 2 Ansätze:
  1. Interpretieren als die Text: Abbrechen bei Fehlern in der Codierung, Testen auf verbotene Zeichen
  2. Testen auf bekannte Magic-Bytes

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.
  Mit Zitat antworten Zitat
PeterPanino

Registriert seit: 4. Sep 2004
1.465 Beiträge
 
Delphi 10.4 Sydney
 
#5

AW: Datei auf Indikatoren für Binärdatei testen?

  Alt 9. Mai 2015, 14:57
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;
  Mit Zitat antworten Zitat
Dejan Vu
(Gast)

n/a Beiträge
 
#6

AW: Datei auf Indikatoren für Binärdatei testen?

  Alt 9. Mai 2015, 15:41
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.
  Mit Zitat antworten Zitat
PeterPanino

Registriert seit: 4. Sep 2004
1.465 Beiträge
 
Delphi 10.4 Sydney
 
#7

AW: Datei auf Indikatoren für Binärdatei testen?

  Alt 9. Mai 2015, 15:52
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.
Ist viel zu aufwendig und unsicher. Meine bisherigen Tests haben gezeigt, dass die Prüfung auf verbotene ControlBytes und Doppel-NullBytes sehr zuverlässig ist. Bitte zeigt mir auch nur EINE Datei, wo diese Prüfung nicht funktioniert hat.
  Mit Zitat antworten Zitat
mjustin

Registriert seit: 14. Apr 2008
3.006 Beiträge
 
Delphi 2009 Professional
 
#8

AW: Datei auf Indikatoren für Binärdatei testen?

  Alt 9. Mai 2015, 16:08
Ist viel zu aufwendig und unsicher. Meine bisherigen Tests haben gezeigt, dass die Prüfung auf verbotene ControlBytes und Doppel-NullBytes sehr zuverlässig ist. Bitte zeigt mir auch nur EINE Datei, wo diese Prüfung nicht funktioniert hat.
Einige Beispiele sind unter https://de.wikipedia.org/wiki/Unicod...rmation_Format zu finden. UTF-32 enthält doppelte Null-Bytes, UTF-16 enthält auch "verbotene" ControlBytes:

Zitat:
00 6D|00 6B|00 3A|04 1F|04 40|04 3E|04 3C|04 35|04 3D|04 30 | UTF-16BE
m |k |: |П |р |о |м |е |н |а | mk:Промена

3E 04 00 00|3C 04 00 00|35 04 00 00|3D 04 00 00|30 04 00 00 | UTF-32LE
00 00 04 3E|00 00 04 3C|00 00 04 35|00 00 04 3D|00 00 04 30 | UTF-32BE
о |м |е |н |а | омена
Michael Justin

Geändert von mjustin ( 9. Mai 2015 um 16:10 Uhr)
  Mit Zitat antworten Zitat
PeterPanino

Registriert seit: 4. Sep 2004
1.465 Beiträge
 
Delphi 10.4 Sydney
 
#9

AW: Datei auf Indikatoren für Binärdatei testen?

  Alt 9. Mai 2015, 16:15
Kann man davon ausgehen, dass UTF-16- und UTF-32-Dateien statistisch signifikant so gut wie immer einen BOM enthalten?
  Mit Zitat antworten Zitat
Dejan Vu
(Gast)

n/a Beiträge
 
#10

AW: Datei auf Indikatoren für Binärdatei testen?

  Alt 9. Mai 2015, 16:38
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?
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 5  1 23     Letzte »    

 

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:09 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz