Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi Datei auf Indikatoren für Binärdatei testen? (https://www.delphipraxis.net/185028-datei-auf-indikatoren-fuer-binaerdatei-testen.html)

PeterPanino 9. Mai 2015 01:54

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:
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?

himitsu 9. Mai 2015 06:27

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.

Bernhard Geyer 9. Mai 2015 08:05

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 (http://en.wikipedia.org/wiki/List_of_file_signatures) gibts hierfür eine kleine Liste

BUG 9. Mai 2015 09:39

AW: Datei auf Indikatoren für Binärdatei testen?
 
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.

PeterPanino 9. Mai 2015 13:57

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;

Dejan Vu 9. Mai 2015 14:41

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.

PeterPanino 9. Mai 2015 14:52

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

Zitat von Dejan Vu (Beitrag 1300829)
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.

mjustin 9. Mai 2015 15:08

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

Zitat von PeterPanino (Beitrag 1300830)
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
о |м |е |н |а | омена


PeterPanino 9. Mai 2015 15:15

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?

Dejan Vu 9. Mai 2015 15:38

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?

BUG 9. Mai 2015 15:50

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

Zitat von PeterPanino (Beitrag 1300833)
Kann man davon ausgehen, dass UTF-16- und UTF-32-Dateien statistisch signifikant so gut wie immer einen BOM enthalten?

Auf keinen Fall! zB. für XML ist es nicht erforderlich.

PeterPanino 9. Mai 2015 16:03

AW: Datei auf Indikatoren für Binärdatei testen?
 
Wie ich schon zu Anfang sagte: Ich bin mir der Problematik dieser Unterscheidung bewusst. Letztlich wird es wohl darauf hinauslaufen, für welchen speziellen Zweck man die Unterscheidung benötigt. Denn man könnte den Aufwand auf die Spitze treiben, indem man z.B. eine semantische Prüfung für alle existierenden Sprachen einbaut usw.

Könnt ihr aber die heuristische Prüfung etwas näher spezifizieren, vielleicht sogar mit etwas Code unterlegen (bezogen auf die obige Funktion).

PeterPanino 9. Mai 2015 16:21

AW: Datei auf Indikatoren für Binärdatei testen?
 
Mir ist gerade ein Gedanke gekommen, wie man eine Heuristik abseits von BOM & Co. implementieren könnte: Es müsste doch möglich sein, eine Art statistischen "Streuungs"-Faktor (oder grob gesagt "statistischer Fingerabdruck") der Bytes zu berechnen, der bei "Binärdateien" signifikant von "Textdateien" abweichen sollte. Was haltet ihr davon?

Perlsau 9. Mai 2015 17:37

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

Dein Problem zeigt gewisse Ähnlichkeiten zu diesem dort :?

PeterPanino 9. Mai 2015 20:43

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

Zitat von Perlsau (Beitrag 1300847)
zeigt

Ich glaube, dass du einiges missverstehst ... vielleicht ist es die Perspektive?

Dejan Vu 9. Mai 2015 21:00

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

Zitat von PeterPanino (Beitrag 1300840)
Mir ist gerade ein Gedanke gekommen...eine Art statistischen "Streuungs"-Faktor (oder grob gesagt "statistischer Fingerabdruck") der Bytes zu berechnen, der bei "Binärdateien" signifikant von "Textdateien" abweichen sollte. Was haltet ihr davon?

Zitat:

Zitat von PeterPanino (Beitrag 1300830)
Ist viel zu aufwendig und unsicher. Meine bisherigen Tests haben gezeigt, ..

:lol: Das ist genau das, was ich vorgeschlagen habe: Einige Zeichen können in Textdateien nicht vorkommen, aber auf der anderen Seite müsste man noch etwas genauer analysieren, was der Unterschied zwischen einer Datei ist, die einen Text enthält, und einer 'Binärdatei', die zufällig nur Buchstaben enthält.
Aber deine Idee ist natürlich viel besser. Klar. ;-)

Perlsau 9. Mai 2015 21:18

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

Zitat von PeterPanino (Beitrag 1300868)
Zitat:

Zitat von Perlsau (Beitrag 1300847)
zeigt

Ich glaube, dass du einiges missverstehst ... vielleicht ist es die Perspektive?

Was meinst du damit, ich würde einiges, insbesondere die Perspektive, mißverstehen? Welche Perspektive meinst du? Könntest du vielleicht etwas genauer bezeichnen, was ich deiner Ansicht nach mißverstehe? Wie sonst sollte ich mein Mißverständnis nachvollziehen und auflösen können?

Die Menge der verschiedenen Dateiformate in Verbindung mit verschiedenen Sprachen ist so zahlreich, daß mir dein Ansinnen schier unmöglich sicher zu lösen scheint. Ist eine gezippte Textdatei noch eine Textdatei? Oder eine verschlüsselte Textdatei? Ist eine RTF-Datei mit Grafiken und Ole-Objekten eine gemischte Datei? Oder eine Exe-Datei mit zahlreichen lesbaren Textabschnitten?

Gehe ich richtig in der Annahme, daß du eigentlich herausfinden möchtest, ob eine Datei binär übertragen werden soll oder nicht?

Was man wirklich einigermaßen sicher herausfinden kann ist, ob eine Datei einem bekannten Format entspricht, z.B. JPEG oder ASCII oder eben auch Executables oder XML etc., wie das z.B. das Programm OpenWith macht. Erst dann, wenn eine Datei keiner der bekannten Dateiformate zugeordnet werden kann, sollte man tiefergehende Analysemethoden einsetzen. Meines Wissens nach gibt es bislang keine Software und keinen bekannten Algorithmus, um Binärdateien zuverlässig von Textdateien unterscheiden zu können.

Mir scheint es daher sinnvoll, dich auf die im Zusammenhang mit deinem Projekt auftretenden Dateiformate zu konzentrieren bzw. zu beschränken, falls das irgendwie möglich ist und nicht potentiell alle bekannten und unbekannten Dateiformate auftreten könnten. Der entsprechende Wikipedia-Artikel bietet eine gute Einstiegsseite zu diesem Thema, insbesondere der Link zur Liste der Dateinamenserweiterungen ist zu empfehlen. Wenn du dann alle denkbaren Dateiformate in deine Prüfung integriert hast, wird kaum noch was übrigbleiben, das keinem bekannten Dateiformat entspricht. Weitere Links:

Informationstechnische Grundlagen (ITG)/ Dateiformate
Übliche Dateitypen
Dateiformate für das elektronische Publizieren

PeterPanino 9. Mai 2015 21:56

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

Zitat von Dejan Vu (Beitrag 1300873)
Aber deine Idee ist natürlich viel besser. Klar. ;-)

Kinder, es ist doch genug Sand für alle zum Spielen da ...

himitsu 9. Mai 2015 22:10

AW: Datei auf Indikatoren für Binärdatei testen?
 
Nur um das Ganze nochmal kurz zu erklären:

* man kann nicht prüfen "ist das eine Textdatei"
* man kann nur prüfen "ist das keine Datei eines/mehrerer bestimmter Textformate" (vermutlich ungültige Zeichen/Kodierungen enthalten)
* Kodierungen ala UTF-8 haben den Vorteil, daß sie erkennbare/prüfbare Strukturen besitzen (solange Nicht-ASCII-Zeichen enthalten sind)
* soll es genauer sein, dann muß man eine linguistische Analyse vornehmen (also auf den Inhalt, ob der einem erlaubten Format entspricht)
* 100%ig sicher kann aber niemals etwas werden

Man muß also zuerst versuchen die Kodierung zu erkennen und kann sich nach Dekodierung den Inhalt ansehn.

PeterPanino 9. Mai 2015 22:11

AW: Datei auf Indikatoren für Binärdatei testen?
 
Vielleicht sollte ich das, was ich in der Eingangsfrage gesagt habe, nochmals wiederholen, um Missverständnisse wie jenes von "perlsau" aufzuklären: Ich habe nicht gesagt, dass ich den Anspruch habe, ein perfektes Unterscheidungskriterium für Text- und Binärdateien zu schaffen. (Denn das kann es nicht geben). Ich habe ausdrücklich danach gefragt, welche weiteren Indikatoren für Binärdateien es noch geben könnte. Nichts anderes. Da kam der nützliche Hinweis zu den ControlBytes und zu den Doppel-NullBytes, was ich auch umgesetzt habe. Nochmals danke dafür. Auch für alle anderen sachlichen Anregungen vielen Dank! Aber bitte sachlich und erwachsen bleiben ...

PeterPanino 9. Mai 2015 22:18

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

Zitat von himitsu (Beitrag 1300881)
* man kann nur prüfen "ist das keine Datei eines/mehrerer bestimmter Textformate" (vermutlich ungültige Zeichen/Kodierungen enthalten)
* 100%ig sicher kann aber niemals etwas werden

GENAU. Deshalb habe ich meine Funktion auch so angelegt, dass auf Indikatoren für Binärdateien geprüft wird (und nicht auf Indikatoren für Textdateien). Und das Verfahren an sich kann immer nur eine ANNÄHERUNG sein. Außerhalb dieser Funktion wird in meinem Programm natürlich noch anderes wie etwa Datei-Endungen usw. geprüft.

redox 9. Mai 2015 22:38

AW: Datei auf Indikatoren für Binärdatei testen?
 
IMHO sollten mit #19 von himitsu und #20 von PeterPanino alle abklärungsbedürftigen Ansätze abgehandelt sein.

Für mich z.B. ist es nur *wahrscheinlich* ermittelbar, ob eine Datei "menschenlesbaren Text" enthält, nicht *absolut*.

"Menschenlesbarer Text" enthält immer ein Leerzeichen zwischen den Wörtern (in den mir bekannten Sprachen).

Just my two cents :oops:

PeterPanino 9. Mai 2015 23:02

AW: Datei auf Indikatoren für Binärdatei testen?
 
Übrigens: Ich benötige die Funktion dafür, um zu entscheiden, ob der Inhalt einer Datei in eine PDF-Datei als Text ausgegeben werden kann oder nicht. Deshalb ist für diesen Zweck allein maßgeblich, dass die Datei KEINE BINÄRDATEI ist.

p80286 9. Mai 2015 23:28

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

Zitat von PeterPanino (Beitrag 1300883)
wird in meinem Programm natürlich noch anderes wie etwa Datei-Endungen usw. geprüft.

Nunja Datei-Endungen...
erfolgsversprechender sind da schon eher die "Magic Bytes".
Ich vermute, daß ein hoher Anteil an "e" und x0D0A auf eine Textdatei verweist, gegen eine Textdatei würden Push/Pop-Sequenzen mehrere NOPs und #00 sprechen.
Eine weitere Möglichkeit wäre es, Buchstabenkombinationen, die sprachspezifisch sind auf ihr Vorkommen zu prüfen.

Gruß
K-h

PeterPanino 10. Mai 2015 00:16

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

Zitat von p80286 (Beitrag 1300896)
Ich vermute, daß ein hoher Anteil an "e" und x0D0A auf eine Textdatei verweist, gegen eine Textdatei würden Push/Pop-Sequenzen mehrere NOPs und #00 sprechen. Eine weitere Möglichkeit wäre es, Buchstabenkombinationen, die sprachspezifisch sind auf ihr Vorkommen zu prüfen.

Danke für deine Antwort.

Wie gesagt, ich möchte nur prüfen, ob es keine Binärdatei ist.

Könntest du mir bitte erklären, was du mit "Push/Pop-Sequenzen mehrere NOPs" meinst?

#00 Habe ich ja schon ausgeschlossen (immer mit dem Kriterium der annähernden Wahrscheinlichkeit).

redox 10. Mai 2015 00:54

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

Zitat von PeterPanino (Beitrag 1300890)
Übrigens: Ich benötige die Funktion dafür, um zu entscheiden, ob der Inhalt einer Datei in eine PDF-Datei als Text ausgegeben werden kann oder nicht. Deshalb ist für diesen Zweck allein maßgeblich, dass die Datei KEINE BINÄRDATEI ist.

Denn sie wissen nicht, was sie tun :twisted:

Luckie 10. Mai 2015 01:23

AW: Datei auf Indikatoren für Binärdatei testen?
 
Ich kacke mal Korinthen. :stupid: Jede Datei ist eine Binärdatei, da sie letztendlich alle auf dem Datenträger nur aus Nullen und Einsen besteht. Letztendlich kommt es auf die Interpretation der Anwendung drauf an, wie die Nullen und Einsen dargestellt werden.

Zitat:

Ich benötige die Funktion dafür, um zu entscheiden, ob der Inhalt einer Datei in eine PDF-Datei als Text ausgegeben werden kann oder nicht.
Öhm, PDF ist PDF. :roll:

Perlsau 10. Mai 2015 01:25

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

Zitat von PeterPanino (Beitrag 1300890)
Übrigens: Ich benötige die Funktion dafür, um zu entscheiden, ob der Inhalt einer Datei in eine PDF-Datei als Text ausgegeben werden kann oder nicht. Deshalb ist für diesen Zweck allein maßgeblich, dass die Datei KEINE BINÄRDATEI ist.

Ahh ... jetzt verstehe ich erst, welchem Zweck das Ganze dienen soll. Du kannst aber dennoch nicht jede Textdatei einfach so "in eine PDF-Datei als Text ausgeben", z.B. Word- und RTF-Dateien mit ihren mannigfaltigen Steuerzeichen oder Vektor-Dateien von Zeichenprogrammen wie CorelDraw, PostScript-Dateien usw. Das wäre für einen reinen Anwender auch nicht wirklich lesbar. Interessant hier ist der Artikel bei Wikipedia über Austauschformate, aber auch:

Austauschformat bei IT Wissen
Warum PDF kein Austauschformat ist

Der Hinweis, auf das Vorkommen von e oder E zu prüfen, da dieser Buchstabe in der deutschen Sprache überdurchschnittlich häufig vorkommt, hilft bei anderen Sprachen nicht unbedingt weiter, siehe dazu auch die Google-Ergebnisse zum Begriff. Am besten scheint mir der Hinweis auf regelmäßig vorkommende Leerzeichen dazu geeignet, eine Datei automatisiert als Text zu identifizieren. Allerdings sind CSV-Dateien (Comma Separated Values) auch Textdateien, die möglicherweise kaum Chr(32) bzw. $20 enthalten. Da es eine absolute Gewißheit, ob Textdatei oder nicht, wie hier bereits mehrfach betont, auf automatisierte Weise nicht geben kann, halte ich es nicht wirklich für abwegig, auf die Frage des Klosterschülers nach einer Prüfmethode für eine Internetverbindung hinzuweisen, die zum selben Ergebnis führt.

Wenn es nur um die deutsche Sprache geht, hilft vielleicht die Liste der häufigsten Wörter der deutschen Sprache, ebenfalls bei Wikipedia.

Was zur Lösung des Problems noch weiterhelfen würde, ist die bereits mehrfach gestellte, aber bislang unbeantwortete Frage, wie du eine Textdatei definierst: PostScript ist auch Text, Unit-Dateien enthalten lesbaren Text usw.

Wieso antwortest du nicht auf meine Fragen: "Was meinst du damit, ich würde einiges, insbesondere die Perspektive, mißverstehen? Welche Perspektive meinst du? Könntest du vielleicht etwas genauer bezeichnen, was ich deiner Ansicht nach mißverstehe? Wie sonst sollte ich mein Mißverständnis nachvollziehen und auflösen können?"

PeterPanino 10. Mai 2015 09:01

AW: Datei auf Indikatoren für Binärdatei testen?
 
Nochmals vielen Dank für all die sicherlich gut gemeinten Ratschläge zur Erkennbarkeit von Textdateien, aber trotzdem möchte ich nochmal auf den Titel dieses Themas und somit auf die Ausgangsfrage hinweisen: "Datei auf Indikatoren für Binärdatei testen?". Die Frage war also nicht "Datei auf Indikatoren für Textdatei testen?". Das Eine ist nicht das Gegenteil vom Anderen, wegen der prinzipiellen Restunsicherheit sowohl bei Ein- als auch Ausschlusskriterien. Wie bereits dargelegt, habe ich mich auf meinen Zweck bezogen für die AUSschließung von Binärdateien entschieden. Ich halte diese Methodik für nicht kompatibel mit der EINschließung von Textdateien. Empirisch gesehen scheint die Ausschlussmethode bessere Ergebnisse zu produzieren.

PeterPanino 10. Mai 2015 13:09

AW: Datei auf Indikatoren für Binärdatei testen?
 
Ich habe jetzt den Hinweis von @mjustin (Posting #8) berücksichtigt, dass UTF-32-enkodierte Dateien auch Doppel-NullBytes enthalten können und deshalb eine Prüfung auf UTF-32 BOM eingefügt (BE und LE), wenn ein Doppel-NullByte angetroffen wird, da ich optimistischerweise davon ausgehe, dass UTF-32-enkodierte Dateien einen BOM enthalten. Damit wird die Rest-Unsicherheit für den Ausschluss von Binärdateien verkleinert. Eine weitere Verkleinerung dieser Rest-Unsicherheit bei einem Doppel-NullByte-Vorkommen in einer Datei ohne UTF-32 BOM könnte man nur durch eine aufwendige statistische oder linguistische Analyse der in der Datei enthaltenen Bytes erreichen.

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;
  BOM_UTF32_LSB: array [0..3] of Byte = ($FF,$FE,$00,$00);
  BOM_UTF32_MSB: array [0..3] of Byte = ($00,$00,$FE,$FF);
var
  Reader: TStreamReader;
  Ch: AnsiChar;
  c: Integer;
  PreviousCharWasNullByte: Boolean;
  ForbiddenControlCharsCount: Integer;

  function HasUTF32BOM(S: TStream): Boolean;
  var
    SavedPos: Int64;
    Buf: TBytes;
  begin
    SetLength(Buf, 4);
    SavedPos := S.Position;
    Result := False;
    try
      S.Seek(0, soBeginning);
      if S.Read(Buf, 4) = 4 then
      begin
        Result := ((Buf[0] = BOM_UTF32_LSB[0])
               and (Buf[1] = BOM_UTF32_LSB[1])
               and (Buf[2] = BOM_UTF32_LSB[2])
               and (Buf[3] = BOM_UTF32_LSB[3]))
               or
                  ((Buf[0] = BOM_UTF32_MSB[0])
               and (Buf[1] = BOM_UTF32_MSB[1])
               and (Buf[2] = BOM_UTF32_MSB[2])
               and (Buf[3] = BOM_UTF32_MSB[3]));
      end;
      CodeSite.Send('HasUTF32BOM', Result);
    finally
      S.Position := SavedPos;
    end;
  end;
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 := HasUTF32BOM(Reader.BaseStream); // 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;
So bleibt als nächster Schritt nur noch die zusätzliche Prüfung auf UTF-16 BOM beim Antreffen der Mindestzahl von verbotenen ControlBytes.

PeterPanino 10. Mai 2015 16:21

AW: Datei auf Indikatoren für Binärdatei testen?
 
So, jetzt habe ich auch die UTF-16-Prüfung eingebaut:

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;
  BOM_UTF32_LSB: array [0..3] of Byte = ($FF,$FE,$00,$00);
  BOM_UTF32_MSB: array [0..3] of Byte = ($00,$00,$FE,$FF);
  BOM_UTF16_LSB: array [0..1] of Byte = ($FF,$FE);
  BOM_UTF16_MSB: array [0..1] of Byte = ($FE,$FF);
var
  Reader: TStreamReader;
  Ch: AnsiChar;
  c: Integer;
  PreviousCharWasNullByte: Boolean;
  ForbiddenControlCharsCount: Integer;

  function HasUTF32BOM(S: TStream): Boolean;
  var
    SavedPos: Int64;
    Buf: TBytes;
  begin
    SetLength(Buf, 4);
    SavedPos := S.Position;
    Result := False;
    try
      S.Seek(0, soBeginning);
      if S.Read(Buf, 4) = 4 then
      begin
        Result := ((Buf[0] = BOM_UTF32_LSB[0])
               and (Buf[1] = BOM_UTF32_LSB[1])
               and (Buf[2] = BOM_UTF32_LSB[2])
               and (Buf[3] = BOM_UTF32_LSB[3]))
               or
                  ((Buf[0] = BOM_UTF32_MSB[0])
               and (Buf[1] = BOM_UTF32_MSB[1])
               and (Buf[2] = BOM_UTF32_MSB[2])
               and (Buf[3] = BOM_UTF32_MSB[3]));
      end;
      CodeSite.Send('HasUTF32BOM', Result);
    finally
      S.Position := SavedPos;
    end;
  end;

  function HasUTF16BOM(S: TStream): Boolean;
  var
    SavedPos: Int64;
    Buf: TBytes;
  begin
    SetLength(Buf, 2);
    SavedPos := S.Position;
    Result := False;
    try
      S.Seek(0, soBeginning);
      if S.Read(Buf, 2) = 2 then
      begin
        Result := ((Buf[0] = BOM_UTF16_LSB[0])
               and (Buf[1] = BOM_UTF16_LSB[1]))
               or
                  ((Buf[0] = BOM_UTF16_MSB[0])
               and (Buf[1] = BOM_UTF16_MSB[1]));
      end;
      CodeSite.Send('HasUTF16BOM', Result);
    finally
      S.Position := SavedPos;
    end;
  end;
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 := HasUTF32BOM(Reader.BaseStream); // 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 := HasUTF16BOM(Reader.BaseStream) or HasUTF32BOM(Reader.BaseStream); // 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;
Wer jetzt noch eine Datei in freier Wildbahn findet, die von dieser Funktion falsch erkannt wird, der kriegt ein Stück vom übriggebliebenen Muttertagskuchen! ;-)

Perlsau 10. Mai 2015 22:14

AW: Datei auf Indikatoren für Binärdatei testen?
 
Da du die Frage nach der Definition einer Textdatei bzw. einer Binärdatei bislang genauso wenig beantwortet hast wie einige andere Fragen zum Problem, wird dir wohl kaum jemand eine von deinem Algorithmus nicht erfaßte Datei liefern können (wollen).

PeterPanino 11. Mai 2015 12:33

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

Zitat von Perlsau (Beitrag 1300944)
Da du die Frage nach der Definition einer Textdatei bzw. einer Binärdatei bislang genauso wenig beantwortet hast wie einige andere Fragen zum Problem, wird dir wohl kaum jemand eine von deinem Algorithmus nicht erfaßte Datei liefern können (wollen).

Zunächst einmal ganz liebe Grüße nach Karlsruhe. Ich habe in der Vergangenheit mehrere sehr nette Menschen aus Karlsruhe getroffen, demnach muss dort ein guter Menschenschlag leben. :)

Ich wundere mich aber über den Inhalt deines Postings. Ich habe diese Frage (ist es überhaupt eine Frage?) in diesem Faden bereits mehrmals sehr ausführlich beantwortet und werde das deshalb hier nicht mehr tun. Im übrigen brauchst du nur meinen Code zu lesen, um zu merken, dass dieser nach dem Ausschlussprinzip funktioniert. Und mein Code funktioniert ausgezeichnet. Wenn du einen Fehler findest, bist du herzlich eingeladen, diesen aufzuzeigen. Denn dazu ist dieses Forum ja da.

Und ich bitte dich, nochmals den TITEL dieses Themas zu lesen: "Datei auf Indikatoren für Binärdatei testen?". Ich nehme mal an, dass du sinnerfassend lesen kannst.

Ich wünsche dir einen schönen Tag!

Perlsau 11. Mai 2015 12:55

AW: Datei auf Indikatoren für Binärdatei testen?
 
Im Nachhinein das Eingangsposting zu editieren, um peinlich empfundener, aber nicht geäußerter Kritik an der Frageformulierung auszuweichen, ist auch nicht gerade die feine englische Art und läßt zumindest einen Mangel an Aufrichtigkeit erkennen. Damit läßt du diejenigen, die versucht haben, auf deine ursprüngliche Frage zu antworten, ziemlich dumm aussehen. Ich wette, dessen bist du dir voll bewußt. Nicht sehr erfreulich für die Forenteilnehmer, die versucht haben, dir behilflich zu sein ...

PeterPanino 11. Mai 2015 13:02

AW: Datei auf Indikatoren für Binärdatei testen?
 
Gehörst du irgendeiner ideologischen oder religiösen Sekte an? Offensichtlich versuchst du zu provozieren oder suchst Streit, weil du vielleicht nichts Besseres zu tun hast. Ich werde von nun an auf deine Postings nicht mehr antworten.

p80286 11. Mai 2015 13:47

AW: Datei auf Indikatoren für Binärdatei testen?
 
Nachdem ich mir mal neuere Programme angeschaut habe, das ist nicht mehr so signifikant wie es war aber trotzdem
push eax x50=P

push ebx x53=S

push esi x56=V
push edi x57=W

oder xor eax,eax x33C0

Gruß
K-H

(ich denke es ist klar, daß man damit nur die Wahrscheinlichkeit erhöhn kann. Für Sicherheit fehlt da noch einiges.)

PeterPanino 11. Mai 2015 14:14

AW: Datei auf Indikatoren für Binärdatei testen?
 
Danke. Ja, eine Prüfung auf MagicBytes könnte ich noch einbauen.

p80286 11. Mai 2015 15:44

AW: Datei auf Indikatoren für Binärdatei testen?
 
Das wäre meiner Meinung nach das sinnvollste, wobei Du nicht aus den Augen verlieren darfst wofür es gut sein soll.

Zitat:

Zitat von Luckie (Beitrag 1300907)
Ich kacke mal Korinthen. :stupid: Jede Datei ist eine Binärdatei, da sie letztendlich alle auf dem Datenträger nur aus Nullen und Einsen besteht. Letztendlich kommt es auf die Interpretation der Anwendung drauf an, wie die Nullen und Einsen dargestellt werden.

Dem ist kaum zu widersprechen, darum bitte immer im Hinterkopf behalten!

Gruß
K-H

PeterPanino 11. Mai 2015 16:29

AW: Datei auf Indikatoren für Binärdatei testen?
 
Liste der Anhänge anzeigen (Anzahl: 1)
Der wichtigste Bestandteil bei der Entwicklung ist immer der Praxistest (dieses Forum heißt ja "Delphi-PRAXIS"). Deswegen bitte ich euch, die Funktion (s. #31) an möglichst vielen Dateien zu testen und mir positive und negative Ergebnisse zu melden, um so auch aus dem Feedback der praktischen Anwendung heraus die Funktion zu verbessern. Was ja wiederum im Interesse der Gemeinschaft der Forumsteilnehmer liegt.

EDIT: Um das Testen zu erleichtern, habe ich hier mal schnell das Testprojekt angehängt.

Perlsau 11. Mai 2015 16:43

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

Zitat von PeterPanino (Beitrag 1301025)
Gehörst du irgendeiner ideologischen oder religiösen Sekte an? Offensichtlich versuchst du zu provozieren oder suchst Streit, weil du vielleicht nichts Besseres zu tun hast. Ich werde von nun an auf deine Postings nicht mehr antworten.

Das ist doch Kindergarten-Niveau, was du hier bringst: Erst weist du darauf hin, daß in meiner Stadt nur liebe Menschen leben, außer mir natürlich, nur um anschließend sofort anzudeuten, ich wäre intellektuell zu beschränkt, um überhaupt den Sinn von Texten erfassen zu können. Zuvor änderst du deinen Ursprungstext, damit einige der Fragen, die man dir zwischendurch gestellt hat, nicht mehr greifen und als blödsinnig angesehen werden müssen, und reagierst äußerst sauer, wenn man dich darauf hinweist, daß das nicht wirklich nett ist.

Nun unterstellst du mir auch noch Sektenmitgliedschaft? Sag mal, geht's noch??? Bleib doch mal auf dem Teppich. Deine vermeintliche Drohung, auf meine Postings nicht mehr einzugehen, ist doch in Wirklichkeit gar keine, denn das hast du erstens zuvor ja auch nicht gemacht, und zweitens wäre es nicht weiter schlimm, wenn du nicht antwortest. Du mußt niemandem antworten, du kannst dir aussuchen, wem du antwortest, du kannst auch überhaupt niemandem antworten, es steht dir frei.

Daß ich nachfragte, weshalb du diverse Fragen (die ja nicht nur von mir kamen) nicht beantwortest, obwohl doch zumindest die Frage danach, wie du Text- bzw. Binärdateien definierst, nicht nur berechtigt scheint, sondern für deine Problemstellung in der Tat signifikant und daher äußerst relevant ist, wirst du mir wohl kaum verübeln, oder?

Tatsache ist: Weder habe ich dich beleidgt noch dich sonst irgendwie herabzusetzen gesucht, was eine derart kindische, ja man könnte fast sagen trotzige Antwort von deiner Seite provoziert haben könnte. Bitte erkläre mir doch einmal, von mir aus auch via PM, wo ich dich deiner Ansicht nach provoziert haben soll. Ich habe mir aus meiner Sicht große Mühe gegeben, dir Informationen im Zusammenhang mit deinem Problem zu liefern. Du mußt natürlich nich darauf antworten, auch nicht auf meine Nachfragen, aber nun derart zu reagieren und dich provoziert zu fühlen, ist nun wirklich nicht angebracht. Äußere persönliche Kritik, die nichts mit dem jeweiligen Thema zu tun hat, doch bitte in Zukunft via Persönlicher Mail, denn das interessiert die anderen vermutlich eher weniger.

Nachtrag: Ich empfinde es als ein wenig unverschämt, hier die Usergemeinde dazu mißbrauchen zu wollen, Arbeit zu erledigen, die im Grunde du zu machen hast. Weshalb testest du deinen Code nicht einfach selbst? Oder glaubst du wirklich, daß die hier größtenteils werktätigen User die Zeit & Lust aufbringen, deine Programme zu testen, wo du noch nicht einmal die einfachsten Antworten zum besseren Verständnis deines Problems mitzuteilen bereit bist? Den eigentlichen Zweck deiner Anstrengungen hast du uns erst im Posting Nr. 27 verraten, das gehört aber gleich ins erste Posting, damit man als hilfsbereiter User weiß, worauf's ankommt. Von wegen mangelhafte Fähigkeit zur Texterfassung: Du solltest dir vor dem Posten überlegen, wie du eine Frage am verständlichsten rüberbringst, und nicht nachträglich das Eingangsposting verändern, um Kritik an deinen Formulierungsfähigkeiten auszuweichen. Du verweigerst zudem weitere Auskünfte und fühlst dich offenbar von entsprechenden Anfragen provoziert. Ich verstehe dein Verhalten nicht.


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:41 Uhr.
Seite 1 von 2  1 2      

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