09.07 Zeichenkodierung

Ein Zeichen wird immer als Code aus Bits und Bytes gespeichert. Je nach Einsatzort oder Herkunft kann dieser Code für identische Zeichen anders aussehen. Deshalb ist es wichtig die Zeichencodierung (charset) einer Zeichenkette zu kennen. Häufig eingesetzte Codierungen sind bspw. UTF-8 oder ISO-8859-1.

Unterschiedliche Zeichenkodierungen

Sie können alle verfügbaren Zeichenkodierungen mit folgendem Code ausgeben:

import java.nio.charset.Charset;

public class CharsetTest {

  public static void main(String[] args) {

    for (String names : Charset.availableCharsets().keySet()) {
      System.out.println(names);
    }
  }
}

Mit der Klasse java.nio.charset.Charset können Sie Ihre Texte in die unterschiedlichen Zeichensätze kodieren bzw. auch wieder dekodieren (encode und decode) lassen. Sehen Sie sich hierzu ein kleines Beispiel an. Ein Text mit Sonderzeichen wird in jeden verfügbaren Zeichensatz konvertiert. Anschließend werden die Bytes, die Bytes als String konvertiert, und die dekodierte Version des Textes auf der Konsole ausgegeben.

package de.jbb.io;

import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.Arrays;

public class CharsetTest {

  public static void main(String[] args) throws UnsupportedEncodingException {

    String text = "123asdÖÄÜß%&/§$";
    for (Charset cs : Charset.availableCharsets().values()) {
      ByteBuffer bytes = cs.encode(text);
      System.out.println(cs.name() + ": ");
      System.out.println("\tBytes : " + Arrays.toString(bytes.array()));
      System.out.println("\tString: " + new String(bytes.array()));
      System.out.println("\tZurück: " + cs.decode(bytes).toString());
    }
  }
}

In anderen Kodierungen lesen und schreiben

Manchmal ist es notwendig, Daten in einer anderen Kodierung zu schreiben/senden, da bspw. ein anderes Programm, welches angesprochen werden soll, eine andere Kodierung erwartet. Für diesen Fall haben Sie in Java die Möglichkeit, bei manchen Streams direkt die gewünschte Zeichenkodierung zu setzen. So können Sie bspw. eine Textdatei in einer anderen Kodierung schreiben und sich den Unterschied ansehen, wenn Sie diese Textdatei wieder mit unterschiedlichen Kodierungen einlesen. Als Beispiel verwenden wir für das Schreiben einen OutputStreamWriter und für das Einlesen einen InputStreamReader. Beiden wird die gewünschte Zeichenkodierung als zweiter Parameter im Konstruktor übergeben. Für den Fall, dass die Zeichenkodierung nicht unterstützt wird, muss eine UnsupportedEncodingException abgefangen werden. Um die Textdatei wieder möglichst komfortabel auszulesen, wird der InputStreamReader gleichzeitig noch von einem BufferedReader umgeben.

File target = new File("C:/test.txt");
OutputStreamWriter osw = null;
InputStreamReader isr = null;
FileOutputStream fos = null;
FileInputStream fis = null;
BufferedReader buffy = null;

try {
  fos = new FileOutputStream(target);
  osw = new OutputStreamWriter(fos, "UTF-16");
  osw.write("Testausgabe mit Sonderzeichen: ÄÜÖäöüß=)(/&§$^°");
}
catch (UnsupportedEncodingException e) {
  e.printStackTrace();
}
catch (IOException e) {
  e.printStackTrace();
}
finally {
  if (osw != null) try { osw.close(); } catch (IOException e) {}
  if (fos != null) try { fos.close(); } catch (IOException e) {}
}

try {
  fis = new FileInputStream(target);
  isr = new InputStreamReader(fis, "UTF-16");
  buffy = new BufferedReader(isr);
  System.out.println(buffy.readLine());
}
catch (UnsupportedEncodingException e) {
  e.printStackTrace();
}
catch (IOException e) {
  e.printStackTrace();
}
finally {
  if (buffy != null) try { buffy.close(); } catch (IOException e) {}
  if (isr != null) try { isr.close(); } catch (IOException e) {}
  if (fis != null) try { fis.close(); } catch (IOException e) {}
}

Sie erhalten als Ausgabe:

Testausgabe mit Sonderzeichen: ÄÜÖäöüß=)(/&§$^°

Lassen Sie aber den Zeichensatz beim Einlesen weg

isr = new InputStreamReader(fis);

Wird die Ausgabe verstümmelt dargestellt.

Zeichenkodierung bei Strings

Wenn Sie nur zeichenkodierte Bytes vorliegen habe (bspw. wenn die so eben geschriebene Datei Byte für Byte eingelesen wird), können Sie einen String aus diesen Bytes mit der gewünschten Kodierung erzeugen. Hierzu übergeben Sie dem String im Konstruktor die Bytes gefolgt von der Kodierung:

try {
  byte[] b = new byte[(int)target.length()];
  fis = new FileInputStream(target);
  fis.read(b);
  System.out.println(new String(b, "UTF-16"));
}
catch (UnsupportedEncodingException e) {
  e.printStackTrace();
}
catch (IOException e) {
  e.printStackTrace();
}
finally {
  if (fis != null) try { fis.close(); } catch (IOException e) {}
}

Codepages und die Windows-Konsole

Als Kodierung können Sie auch Codepages angeben, die Sie nicht über die Charset-Klasse auslesen können – sofern diese vom System unterstützt werden.

Unter einer Codepage versteht man eine Tabelle, in welcher Zeichen unterschiedlichen Kodierungen zugeordnet werden. Siehe auch Wikipedia – Codepage.

So ist es bspw. möglich, durch die Verwendung der Codepage „cp850“ sogar Sonderzeichen und Umlaute auf der Windows-Konsole korrekt auszugeben.

try {
  System.out.println("ÖÄÜß!§$%&/()=");
  System.setOut(new PrintStream(System.out, true, "cp850"));
  System.out.println("ÖÄÜß!§$%&/()=");
}
catch (UnsupportedEncodingException e) {
  e.printStackTrace();
}

Ausgabe:

Í─▄▀!º$%&/()=
ÖÄÜß!§$%&/()=

2 Replies to “09.07 Zeichenkodierung”

  1. Arno

    Schöne Seite, vor allem mit den Beispielen, die man direkt in Eclipse ausprobieren kann.
    Hab das mit den Java Codesets Listings einmal ausprobiert, dabei ist mir aufgefallen, das bei manchen Codesets (4 von 166) eine Exception geworfen wird (NullPointerException oder UnsupportedOperationException).
    Wie kann das sein, dass bei einem offiziell installierten JDK auf meiner Windowsmaschine, bestimmte Codesets wohl kaput sind?
    Wie kann man das überprüfen, bzw. korrigieren?

    Wisst Ihr das?

    mfG
    Arno

Schreibe einen Kommentar

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.