# Textdatei einlesen - erstes Zeichen falsch



## Andi_CH (13. Feb 2012)

Ich sollte eine Konfigurationsdatei einlesen (Attached - eigentlich heisst die Datei nur test.conf, aber das kann ich nicht hochladen ;-) )

Woher kommt es wohl, dass das erste Byte der Zeile "-1" ist?
Kann man so etwas geschickt handeln?
Editiert in Eclipse, Text file encoding für das Projekt UTF-8



```
private boolean parseFile(String fileName) {
		boolean result = true;
		try {
			FileReader fr = new FileReader(fileName);
			BufferedReader br = new BufferedReader(fr);
			String line;
			while ((line=br.readLine()) != null ) {
				line = line.trim();
				System.out.println(line);
// Die Ausgabe sieht ganz normal aus
				for (int i=0; i<2; i++)
					System.out.println(line.charAt(i) + ", byte " + (byte)line.charAt(i));
//, byte -1 (auf der Konsole sie die erste Stelle eher wie ein ; aus)
//#, byte 35
				System.out.println(line.startsWith("#"));
//logischerweise false
```


----------



## maki (13. Feb 2012)

Mit einem hexeditor untersucht (Hex-Editor MX unter Windows) zeigt sich, dass die ersten 3 Bytes "falsch" sind für textdateien:
EF BB BF ..


----------



## HimBromBeere (13. Feb 2012)

Kann es auch sein, dass die Byte-Order-Mark da am Anfang steht? Die mogelt sich da gerne mal rein, sobald deine Textdatei mal auf einer anderen Plattform zu Hause war... ist das erste Zeichen für die Angabe, in welcher Reihenfolge die Bytes ausgewertet werden müssen (Vgl: Byte Order Mark ? Wikipedia)
Einfach mal in einem Texteditor deiner Wahl (nun nicht gerade Notepad, das kann das nicht, z.B. Notepad++ kann das) das BOM umstellen...

EDIT: 


> dass die ersten 3 Bytes "falsch" sind für textdateien:


Die sind nicht falsch, sondern geben nur eine andere Interpretationsreihenfolge an.
Das dürfte das EF BB FB erklären...


----------



## Andi_CH (13. Feb 2012)

Zuerst war es nur eines, jetzt sind es 3 
Tja, eines ist wie die da rein kommen (das ist mir absolut umklar) aber eigentlich laufen meine Anstrengungen dahin, ungültige Zeichen zu verwerfen, denn was jetzt passiert ist, kann immer wieder vorkommen.


```
private boolean isValidChar(char c) {
	return ((byte)c > 19);
}
```

Ist allenfalls suboptimal ;-)


----------



## HimBromBeere (13. Feb 2012)

> Zuerst war es nur eines, jetzt sind es 3


Meinst du dieses ï»¿ ? Das sind tatsächlich drei Bytes...


----------



## maki (13. Feb 2012)

EF BB BF steht nach HimBromBeere für UTF-8, zeig doch mal den Code der die Datei einliest.


----------



## Andi_CH (13. Feb 2012)

Der Code steht im Einganspost
Ich darf mich auf keinen Fall darauf verlassen, dass die config-Dateien mit Eclipse in einer bestimmten Coedierung entstanden sind - vielleicht wurden die mit vi auf Linux oder gar mit "KleinstweichBüroWort" erstellt und als Text gespeichert.

Vielleicht bleibe ich doch beim 
	
	
	
	





```
return (c>=' ')
```
 ;-)


----------



## HimBromBeere (13. Feb 2012)

Hab´s mal aus deiner Datei rausgenommen. Schau mal, ob´s jetzt geht...

EDIT:


> EF BB BF steht nach HimBromBeere für UTF-8


Nicht ganz, es steht für UTF-8 mit BOM... meine hochgeladene Datei ist - wie due sehen kannst - genau 3Byte kleiner, also ohne BOM...


----------



## Andi_CH (13. Feb 2012)

Die Datei befindet sich innerhalb der Projektstrukur und wird ins bin-Verzeichnis kopiert und, so vermute ich mal, somit umcodiert. (Das ist die Notfalldatei, falls keine andere gefunden wird)

Erste Zeile als Bytearray 
[-17, -69, -65, 35, 32, 100, ......

Als jar-externe Datei irgendow im Filesystem deponiert und absolut adressiert funktioniert es problemlos, aber eben ich muss solche Situationen auch bei den "externen" Dateien tolerieren, denn ich kann nicht bestimmen wer in Zukunft die Datei womit ediert.

Ich möchte zwar die Notfalldatei nicht anders behandeln wie die anderen, aber kann (soll?) ich die führenden Bytes ausnutzen? Ignorieren ist vermutlich zukunftssicherer...


----------



## HimBromBeere (13. Feb 2012)

Ist ja Wahnsinn, ich konnte sogar mal zwei JAVA-Schwergewichten was Neues erzählen, jetzt bin ich über alle Maßen beeindruckt...

Wie auch immer, funktioniert das Einlesen der manipulierten Datei denn überhaupt? Denn falls ja heißt das ja schonmal, dass wir auf dem richtigen Weg mit der BOM sind... falls nicht, muss es ja was anderes sein.


----------



## Andi_CH (13. Feb 2012)

öhm - einmal mehr dachte ich, ich hätte mich klar genug ausgedrückt 

Die ausführliche Variante:

Also ja es tut, aber nur wenn ich Datei von dir NICHT in den Projektbereich (src/configuration) kopiere, denn dann wird sie ins bin-Verzeichnis kopiert und umcodiert. Das gibt dann den Bytearry den ich oben gezeigt habe.

Wenn ich eine saubere Datei (zum Beipiel deine) irgendwohin ins Filesystem kopiere und absolut addressiere funktioniert es, aber damit ist ja erst klar wie das entsteht.

Wie ich im konkreten Fall damit umgehen soll ist noch fraglich.

Im Moment mache ich Folgendes


```
private String removeInvalidChar(String pIn) {
		String retVal = "";
		byte[] bArr = pIn.toLowerCase().getBytes();
		for (byte b : bArr) {
			try {
				char c = (char)b;
				if (b > 19)
					retVal += c;
			} catch (Exception e) {}
		}
		return retVal;
	}
```


----------



## Spacerat (13. Feb 2012)

```
public Text(Reader in)
throws IOException
{
	this.txt = new StringBuilder();
	int r;
	char c;
	while((r = in.read()) != -1) {
		if((c = (char) r) == 0) {
			throw new IOException("error reading text");
		}
		txt.append(c);
	}
	in.close();
}
```
@Andy_CH: Mit diesem Teil einer Klasse lese ich Plaintext-Dateien jeglicher Herkunft, auch deine. Allerdings wird dieses BOM am Anfang als kryptische Zeichenfolge interpretiert, lässt sich aber vermutlich filtern. Vllt. hilfts ja.
[EDIT]Ach ja... des BOM merk' ich mir...[/EDIT]


----------



## Andi_CH (13. Feb 2012)

Danke ...
Kaum macht man's richtig... geht's


----------



## Andi_CH (13. Feb 2012)

Jetz habe ich zu lange gewartet mit ändern - gibt es noch eine weiter kreative Idee wie ich "ungültige" Charakter eliminieren kann.


----------



## Spacerat (14. Feb 2012)

Äh... was bitte sind denn nun noch ungültige Charaktäre? Wenn's ein Problem mit meinem Code gibt, würd' ich's gern' wissen.


----------



## Andi_CH (14. Feb 2012)

Das Problem ist, dass ich nicht verstehe wo nun was eliminiert wird und ob ich das wirklich nur hinbekomme wenn ich die Datei Zeichenweise einlese, was mich ehrlich gesagt ein wenig stört.
(Ich bin nun mal ein Mensch der nicht die erste Idee für die Beste hält weil es die erste war)

Ausserdem habe ich nach "einer weiteren kreativen Idee" gefragt, womit ich nicht gesagt habe, dass deine falsch ist.

----

EDIT: Der Code scheint doch nicht zu funktionieren:

Ich hab ein Testprogramm gebaut, der output ist:

-17
-69
-65
35
32
68



```
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

public class Text {

	StringBuilder txt;

	public Text(Reader in) throws IOException {
		this.txt = new StringBuilder();
		int r;
		char c;
		while((r = in.read()) != -1) {
			if((c = (char) r) == 0) {
				throw new IOException("error reading text");
			}
			txt.append(c);
		}
		in.close();
	}

	public static void main(String[] args) {
		final String fileName = "C:/temp/test.conf";
		try {
			Reader rdr = new FileReader(fileName);
			Text t = new Text(rdr);
			for (byte b : t.txt.toString().getBytes()) {
				System.out.println(b);
			}
		} catch (FileNotFoundException e) {
			System.out.println("File not found");
		} catch (IOException e) {
			System.out.println("IOException");
		}
	}
}
```


----------



## XHelp (14. Feb 2012)

Einige Ideen und weiterführende Links kann du auch utf 8 - Byte order mark screws up file reading in Java - Stack Overflow hier beziehen.


----------



## Spacerat (14. Feb 2012)

Die Ausgabe ist vollkommen korrekt. Des BOM liegt im Enhanced ASCII-Bereich also über 127. Die Bytedarstellung is somit negativ. Ich hatte ja schon gesagt, dass man das filtern muss.


----------



## Andi_CH (14. Feb 2012)

... und was bringt mir dann deine Software? Soweit war ich ja schon am Anfang ;-)
Anyway, hier kommt glaub nichts mehr -  Danke allen die mitgewirkt haben.


----------



## Spacerat (14. Feb 2012)

1. Du kannst während des Lesens ggf. überprüfen, ob ein Zeichen im ASCII-Bereich (1 - 127) liegt und
2. Du kannst mit einem Zähler abfragen, ob die BOM-Sequenz vorhanden ist. Ist sie vorhanden, kannst du den Inhalt des Builders "on the fly" korrigieren. Beim zeilenweise Lesen, hast du diese Möglichkeit jedoch nicht.
[EDIT]Obwohl... Ich red' Schwachfug...
	
	
	
	





```
final String BOM = String.valueOf(new char[]{0xEF, 0xBB, 0xBF});
text.replace(BOM, "");
```
[/EDIT]


----------



## Andi_CH (14. Feb 2012)

Ich lese eine Zeile, mache trim(), prüfe ob die Zeile mit "#" beginnt und wenn nicht wird ausgewertet.

Vermutlich werde ich trim() überschreiben.


----------

