# Datei als ASCII text einlesen ?



## Cola_Colin (11. Dez 2010)

Hallo,
ich arbeite gerade daran, einen Code den ich vor gewisser Zeit in C# geschrieben habe in Java umzubauen. Dieser Code ließt eine Replaydatei von einem Computerspiel aus und gibt einen Namen zurück, der von den im Replay enthaltenen Spielern und der Map abhängig ist.
Wenn ich so ein Replay einfach mit Notepad++ öffen, dann sehe ich sowas:







Viel Kauderwelsch, dazwischen aber brauchbare Werte, eine Methode die da meine Daten herausfischt habe ich in C# schon, funktioniert einwandfrei.

Bei Java habe ich aber das Problem, das ich es nicht schaffe den Text so einzulesen, wie ihn Notepad++  ihn mir zeigt. Ich kriege sowas:


> ӯ����L(��w0��&G$ą��QƔ$DEI�D1�0-���xipXP�(�ѡ�N@


anstatt von 


> Replay v1.9



Da ist irgendwo in der Codierung der Wurm drinne.

Wie kann ich mit Java eine Datei als Text einlesen ?
In Notepad++ ist ANSI als Codierung gewählt.
Hab schon irgendwelche Charsets mit dem StreamReader probiert, aber gibt keine wirkliche Änderung.


----------



## Murray (11. Dez 2010)

Diese Datei ist ja eher eine Binär- als eine Text-Datei; insofern solltest Du sie nicht mit einem Reader bearbeiten, sondern mit einem InputStream. Dann kannst Du die einzelnen Bytes als ASCII interpretieren und entscheiden, ob sich dahinter ein druckbares Zeichen verbirgt oder nicht.


----------



## Cola_Colin (11. Dez 2010)

Es gibt also in Java keine Möglichkeit eine Menge an Bytes einfach als ANSI Text zu interpretieren, ohne alles selber zu schreiben ?
Ich muss mir also selber eine Klasse schreiben, die den Text korrekt interpretiert ? 

:S


----------



## XHelp (11. Dez 2010)

Doch, die gibt es. Aber was du brauchst ist eben die Datei byte-Weise einlesen und die richtige Stelle rausfinden. Habe mir gerade ein paar Dateien gezogen, so wie es aussieht ist die Datei wie folgt aufgebaut:

```
SCversion 0x00 0x0D 0x0A 0x00 Repl. Version 0x0D 0x0A NAME 0x00 0x0D 0x0A
```
Nach diesem Muster solltest du auch die Datei einlesen.


----------



## Murray (11. Dez 2010)

Es gibt in Java eine Möglichkeit, eine Menge von Bytes unter Verwendung einer bestimmten Codierung in eine String zu wandeln: http://download.oracle.com/javase/6/docs/api/java/lang/String.html#String(byte[],%20java.lang.String)
Dazu muss man aber a) die Bytes auch als solche gelesen haben (also mit einem InputStream und nicht mit einem Reader, der unter der Haube selbst die Daten als Unicode intrepretiert) und b) das richtige Charset verwenden. Wenn es sich um ANSI-Daten handelt, dann wäre möglicherweise "ISO-8859-1" eine gute Wahl.


----------



## Cola_Colin (11. Dez 2010)

Für meine Methode, die ich für C# programmiert hatte brauchte ich nur genau das, was man in Notepad++ sieht Zeile für Zeile als String.
Ich weiß, dass man sich jetzt mit dem Replayformat von dem Spiel auseinandersetzen kann und es dann direkt binär einlesen kann.
Aber ich habe eben schon eine funktionierende Methode, die als Input eben den String benötigt. 

Kann ich den nicht ohne großen Aufwand kriegen ?

EDIT:
Uff, da muss ich mich dann ja um die Zeilenumbrüche immer noch selber kümmern. 
~.+

Mal schauen, danke für die Denkanstöße.


----------



## XHelp (11. Dez 2010)

Welchen String? Du hast eine X mb große Datei, es gibt keine Methode in Java, die da heißt: gibMirIrgendwieEinStringDerIrgendwoStehtUndSoEinWenigLesbarAussieht(). Ich bin mir ziemlich sicher, dass es die auch nicht in C# gibt.


----------



## Murray (11. Dez 2010)

Cola_Colin hat gesagt.:


> Aber ich habe eben schon eine funktionierende Methode, die als Input eben den String benötigt.
> 
> Kann ich den nicht ohne großen Aufwand kriegen ?


Eine fertige Methode liesEineBinaerDateiUndInterpretierteDieDatenDannAlsANSICodierungUndGibMirEinenEntsprechendenStringZurueck() gibt es nicht.
Es gibt nichtmal eine Methode, mit der man sich den Inhalt einer Datei als byte[] geben lassen könnte.  

Insofern wird es ohne eigene Programmierung an dieser Stelle nicht klappen: allerdings ist das ja nicht wirklich "Rocket-Science", was da erforderlich ist.


----------



## Cola_Colin (11. Dez 2010)

Den String, den man enthält, wenn man so tut als wäre die Datei ASCII-Text.
Da kommen dann, wie in Notepad++ zu sehen, ne Reihe Zeilen bei heraus, die sich immer nach einem Muster verhalten, dass ich ausnutze. Der StreamReader von C# liefert bei seiner Standardcodierung mit dem ersten readLine() die erste Zeile, wie sie auch in Notepad++ zu sehen ist, mit dem zweiten readLine() die zweite u.s.w.


			
				C# hat gesagt.:
			
		

> StreamReader sr = new StreamReader(fullPath) // fullPath ist einfach der Pfad, danach kann man readLine() verwenden.


Delphi kann das btw ähnlich.

Wieso sollte es auch nicht eine Möglichkeit geben eine Datei als Text einzulesen ?

EDIT:
Klar ist das keine Rocketscience, nur das die Namenserkennung ein nettes Gimmick für ein Programm ist, dass ich schreibe und ich eigentlich nur schnell den Code aus C# abschreiben wollte. Bisher habe ich ähnliches in Delphi und C# umgesetzt und dort nie Probleme gehabt, einfach irgendwelche Dateien als Text einzulesen. Wieso auch nicht. Die Dateien sind ne Anreihung von bytes. Die kann ja selbst der Windows-Editor als text interpretieren.

Java kann also nicht einfach ANSI-Textdateien einlesen ?


----------



## Murray (11. Dez 2010)

Versuch mal 

```
Reader rd = new InputStreamReader( new FileInputStream( fullPath), "ISO-8859-1");
```


----------



## XHelp (11. Dez 2010)

Du kannst auch in Java Ascii-Datei einlesen, in dem du irgendwas verwendest, wo du Charset übergeben kannst (z.B. Scanner-Klasse). Aber so ließt man keine Binärdatei.
Btw: Delphi würde beim ersten 0x00 es als EOF interpretieren und aufhören zu lesen (ohne weiteres)


----------



## Murray (11. Dez 2010)

Cola_Colin hat gesagt.:


> Java kann also nicht einfach ANSI-Textdateien einlesen ?


Doch. Man kann alle Dateien einlesen. Man muss nur aufpassen, wie man das dann interpretiert. Aber Schluss mit der Spekulation: zeig uns doch mal Deinen Java-(und nicht den C#-)Code, mit dem Du die Datei einliest.


----------



## Cola_Colin (11. Dez 2010)

Scanner gibt genauso wie der Reader mit der Angabe der Codierung nur Datenmüll zurück.

Es ist doch völlig egal ob man eine Binärdatei so einließt oder nicht. Als ob text nicht auch im Endeffekt nur binäre abgespeichert würde. Fakt ist, wenn ich die Datei als text interpretiere, dann klappt das alles wunderbar. Java kann das scheinbar nicht ~.+
In Delphi hab ich ähnliches definitiv mal gemacht. In der Tat war es nicht genau der gleiche Dateityp. Glaub da kam Null eben erst nach den Infos, die ich wollte.

Ich werde wohl einfach in C# arbeiten. Das Programm, das entstehen soll ist nicht besonders groß. Es tut nicht mehr, als ein Replay aus einer zip zu nehmen, irgendwohin zu kopieren und zu starten. Lohnt nicht da noch nen Aufwand zu betreiben um sich mit den Codierungen rumzuschlagen.

Trotzdem danke für die Hilfe.

EDIT:
Mein Einlesen sieht mit dem Scanner so aus:


```
read = new Scanner(new FileInputStream(fullPath));
```

danach 
	
	
	
	





```
read.nextLine();
```
.

Mit dem Reader hatte ich exakt deinen Beispielcode bereits so drinne. Einziger Unterschied war, dass ich noch einen BufferedReader drumgepackt hatte, da der readLine() bietet.


----------



## XHelp (11. Dez 2010)

Wenn du die Datei byte-Weise einließt, dann kannst du mehr Informationen rausholen. Vor allem auch Typ, Beschreibung, Optionen (ob Cheats aktiviert waren etc), wer gewonnen hat und was auch immer noch in dieser Datei steht. Hier mal ein Bsp: 

```
public class ReplayReader {
	public static Map<String, String> readFile(String path) {
		Map<String, String> resultsMap = new HashMap<String, String>();
		try {
			FileInputStream fis = new FileInputStream(path);
			int i;
			String s="";
			//SC version einlesen
			while ((i=fis.read())>0) { //bis zum ersten 0x00
				s+=(char) i;
			}
			resultsMap.put("sc_version", s);
			while ((i=fis.read())>0) { //bis zum nächsten 0x00 springen
			}
			s = "";
			while ((i=fis.read())>0x0D) { //bis 0x0D
				s+=(char) i;
			}
			resultsMap.put("replay_version", s);
			fis.read();//0x0A überspringen
			
			s = "";
			while ((i=fis.read())>0) { //bis zum nächsten 0x00 springen
				s+=(char) i;
			}
			resultsMap.put("map_name", s);
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return resultsMap;
	}
	
	public static void main(String[] args) {
		Map<String, String> test = readFile("c:/bla.scr");
		Set<String> keySet = test.keySet();
		for (String currentKey:keySet) {
			System.out.println("|"+currentKey+"|:|"+test.get(currentKey)+"|");
		}		
	}
}
```

Wenn du weitere Infos haben willst, würde sich aber eine andere Struktur anbieten.


----------



## Cola_Colin (11. Dez 2010)

Das ist mir klar, es gibt im GPG-Forum auch eine knappe Doku, wie das ganze genau aufgebaut ist.
Es ist nur eben so, dass ich schon eine fertige Methode habe, die mit dem ganzen als String Zeile per Zeile arbeitet und die verwenden wollte. Die funktioniert auch zuverlässig und ist schon eine Weile in Gebrauch.

Das Ziel ist es, die Replays nach Map und Spieler zu benennen. Die Replayversionsnummer und die Spielversion interessieren nicht. Auch Mods und alles andere sind uninteressant. 

Das geht jetzt auch schon ziemlich weit von meiner eigentlichen Frage weg. Die war, wie ich eine x-beliebige Datei als Text interpretiere. Nicht wie ich SupCom-Replays bis ins letzte Details auslese. Die Frage danach hätte ich eher im Forum des Spieles in der Moddingsektion gestellt.

Nochmals Danke, aber dein Vorschlag würde einfach mit einer Kanone auf einen Spatzen schießen. Ich brauche einfach keinen kompletten Parser.


----------



## XHelp (11. Dez 2010)

Dann nimm eben den Vorschlag von Murray, wenn du es komisch machen willst. Der funktioniert, auch wenn du das Gegenteil behauptest.

```
public static String getMapName(String path) {
	String s = "";
	try{
		BufferedReader reader = new BufferedReader( new InputStreamReader( new FileInputStream( path), "ISO-8859-1"));
		reader.readLine();
		reader.readLine();
		s = reader.readLine();
		s = s.substring(0,s.length()-1);
	} catch (UnsupportedEncodingException e) {
		e.printStackTrace();
	} catch (FileNotFoundException e) {
		e.printStackTrace();
	} catch (IOException e) {
		e.printStackTrace();
	}
	return s;
}
```


----------



## Cola_Colin (11. Dez 2010)

Argh. Mein Fehler. Hab zwar das Replay entpackt aber die Methode zur Namenserkennung mit dem zip-File gefüttert.
Da kommt natürlich nichts brauchbare bei heraus.

OK, das war dumm...


----------

