Mittwoch, 14. Oktober 2009

Datenverarbeitung

Man bekommt es ja häufiger mal mit Daten zu tun, die in irgendwelchen Formaten vorliegen und verarbeitet werden wollen. Üblicher Weise sind Eingaben vor deren Verarbeitung auf ihre Richtigkeit zu prüfen. Werden Daten in einem bestimmten Format erwartet, ist eben auch festzustellen, ob die hereingereichten Daten auch diesem Format entsprechen. Tun sie dies nicht, können nicht passende Daten unmittelbar abgelehnt und eine passende Fehlermeldung formuliert werden.

Kommen die zu verarbeitenden Daten aus dem Dateisystem, kann eine Prüfung auf die Dateierweiterung schon einen oberflächlichen Anhaltspunkt liefern. Windows begnügt sich übrigens mit der oberflächlichen Formaterkennung, was durchaus zur Folge haben kann, dass eine Bilddatei als Text deklariert wird, weil die Dateiendung gerade nicht zum Datenformat der Datei passt.

In der Unix Betriebssystemwelt geben sich Programme hingegen ehr selten mit Dateiendungen ab. Die Identifikation des vorliegenden Datenformats findet hier anhand der Magic Bytes - also den ersten vier Bytes der Datei statt. Die ersten vier Bytes eines Jpeg komprimierten Bildes lauten zum Beispiel 0xff 0xd8 0xff 0xe0.

Dateiformaterkennung anhand der Magic Bytes ist für Software immer die erste Wahl, da die Prüfung viel präziser ist, als die Dateiendung aus dem Filesystem. Spätestens, wenn beim Auslesen nur noch ein InputStream vorliegt, kommt man mit den Dateiendungen nicht weiter. So vermeidet man bereits präventiv, dass Daten auf einen Algorithmus losgelassen werden, für den diese gar nicht geeignet sind.

In der Praxis gibt es bereits fertige Bibliotheken, die sich um die Datenformaterkennung kümmern. So gibt es zum Beispiel das Mime Type Detection Utility, das bereits eine Vielzahl an gängigen Datenformaten erkennen kann.

Vor eine besondere Herausforderung wird man bei der Datenformaterkennung von Text gestellt. So wird bei UTF Kodierten Texten noch häufig die verwendete Byte-Reihenfolge (Big- oder Little-Endian) in die ersten zwei Bytes kodiert, spätestens bei ASCII ist aber Schluss. Die Erkennung von ASCII erfordert also echte Kreativität. Mein erster Ideenansatz ging in Richtung Textanalyse - also zum Beispiel zu prüfen, ob ein Text ein übliches Maß an Leerzeichen enthält, was aber nur eine ungenügende Annäherung ist. Ein Blick in den Source des Mime Type Detection Utility förderte noch einen anderen Ansatz zu Tage. Dieser dreht die These um und prüft, ob es sich bei den gegebenen Daten um Binärdaten handeln könnte. Auch dies ist wiederum nur eine Annäherung, aber durchaus praktikabel. So kann bei erwarteten Textdaten zumindest geprüft werden, ob es sich bei den gegebenen Daten eben NICHT um Text handelt.

Ohne lange Umschweife, hier der Source aus dem Mime Type Detection Utility dazu:


 /**
* This is a quick check for the byte array to see if it contains binary data.
* As no known text encoding can have a character containing more than maxNullValues consecutive negative bytes
* method does a quick and dirty elimination of what are probably binary files but should never eliminate possible text files.
*
* It is possible that some binary files will not have maxNullValues consecutive byte
* values especially if it's a small file and will slip through here. Later tests should eliminate these.
*/
public static boolean isBinary(byte[] data) {
// No text file should have 2 or more consecutive NULL values
final int maxNullValues = 2;
int negCount = 0;

for(int i = 0; i < data.length; i++) {
if(data[i] == 0) {
negCount++;
} else {
negCount = 0;
}

if(negCount == maxNullValues) {
return true;
}
}

return false;
}

Dateityp ermitteln

Man bekommt es ja häufiger mal mit Daten zu tun, die in irgendwelchen Formaten vorliegen und verarbeitet werden wollen. Überlicher Weise sind Eingaben vor deren Verarbeitung auf ihre Richtigkeit zu prüfen. Werden Daten in einem bestimmten Format erwartet, ist eben auch festzustellen, ob die hereingereichten Daten auch diesem Format entsprechen. Tun sie dies nicht, können nicht passende Daten unmittelbar abgelehnt und eine passende Fehlermeldung formuliert werden.

Kommen die zu verarbeitenden Daten aus dem Dateisystem, kann eine Prüfung auf die Dateierweiterung schon einen oberflächlichen Anhaltspunkt liefern. Windows begnügt sich übrigens mit der oberflächlichen Formaterkennung, was durchaus zur Folge haben kann, dass eine Bilddatei als Text deklariert wird, weil die Dateiendung gerade nicht zum Datenformat der Datei passt.

In der Unix Betriebssystemwelt geben sich Programme hingegen ehr selten mit Dateiendungen ab. Die Identifikation des vorliegenden Datenformats findet hier anhand der Magic Bytes - also den ersten vier Bytes der Datei statt. Die ersten vier Bytes eines Jpeg komprimierten Bildes lauten zum Beispiel 0xff 0xd8 0xff 0xe0.

Dateiformaterkennung anhand der Magic Bytes ist für Software immer die erste Wahl, da die Prüfung viel präszierer ist, als die Dateiendung aus dem Filesystem. Spätestens, wenn beim Auslesen nur noch ein InputStream vorliegt, kommt man mit den Dateiendungen nicht weiter. So vermeidet man bereits präventiv, dass Daten auf einen Algorithmus losgelassen werden, für den diese gar nicht geeignet sind.

In der Praxis gibt es bereits fertige Bibliotheken, die sich um die Datenformaterkennung kümmern. Eingesetzt habe ich bereits die Mime Type Detection Utility, die bereits eine vielzahl an gängigen Datenformaten erkennen können.

Vor eine besondere Herausforderung wird eine Datenformaterkennungssoftware bei der Erkennung von Text gestellt. So wird bei UTF Kodierten Texten noch häufig die verwendete Byte-Reihenfolge (Big- oder Little-Endian) in die ersten zwei Bytes kodiert, spätestens bei ASCII ist aber schluß. Die Erkennung von ASCII erfordert also echte Kreativität. Mein erster Ideenansatz ging in Richtung Textanalyse - also zum Beispiel zu prüfen, ob ein Text ein übliches Maß an Leerzeichen enthält, was aber nur eine ungenügende Annäherung ist. Ein Blick in den Source des Mime Type Detection Utility förderte noch einen anderen Ansatz zu Tage. Dieses dreht die These um und prüft, ob es sich bei den gegebenen Daten um Binärdaten handeln könnte. Auch dies ist wiederum nur eine Annäherung, aber durchaus praktikabel. So kann bei erwarteten Textdaten zumindestens geprüft werden, ob es sich bei den gegebenen Daten eben NICHT um Text handelt.

Ohne lange Umschweife, hier der Source aus dem Mime Type Detection Utility dazu:
/**
* This is a quick check for the byte array to see if it contains binary data.
*
* As no known text encoding can have a character containing more than maxNullValues consecutive negative bytes
* method does a quick and dirty elimination of what are probably binary files but should never eliminate possible text files.
*
* It is possible that some binary files will not have maxNullValues consecutive byte
* values especially if it's a small file and will slip through here. Later tests should eliminate these.
*/
public static boolean isBinary(byte[] data) {
// No text file should have 2 or more consecutive NULL values
final int maxNullValues = 2;
int negCount = 0;

for(int i = 0; i &lt; data.length; i++) {
if(data[i] == 0) {
negCount++;
} else {
negCount = 0;
}
if(negCount == maxNullValues) {
return true;
}
}
return false;
}

Dienstag, 6. Oktober 2009

Linktip Lesestoff

Angelika Langer stellt eine Vielzahl ihrer Artikel zum online Lesen aus. Ihre Online-Artikel sind größtenteils deutschsprachig und befassen sich mit den Themengebieten Java Performance Tuning, Concurrent Programming, Java Generics, Enumeration Types, Closures und Core Java.


Hier geht es zum Lesestoff