Wie kann man mit Hilfe der Klasse Scanner Daten von der Konsole oder aus einer Datei lesen? v.5.0

Die Klasse Scanner stellt seit Java 5 eine Reihe von Methoden bereit, mit denen man numerische und nicht-numerische Literale aus Strings, Dateien und Eingabe-Strömen (InputStream) ein- und auslesen und mit Hilfe von regulären Ausdrücken filtern kann.

Scanner kann Text aus jedem Objekt lesen, das das Interface Readable implementiert. Das erste Beispiel demonstriert das Einlesen von der Konsole, dem Standard-Eingabestrom System.in. Die hier auf der Kommandozeile eingegebenen und mit <Return> abgeschlossenen Texte werden so lange eingelesen und wieder ausgegeben, bis ein 'q' als Einzelzeichen eingegeben wurde.
Hierzu wird dem Konstruktor des Scanner-Objektes als Quelle der Eingabestrom System.in übergeben. In einer Endlosschleife wird durch die Methode next() der String übernommen und auf die o.a. Abbruchbedingung geprüft. Ist diese erfüllt, so wird die Schleife verlassen, ein Gruß ausgegeben und das Programm beendet. Im anderen Fall läuft die Schleife weiter und die nächste Eingabe wird ausgegeben. Wichtig ist, dass der Scanner zum Schluss mit close() geschlossen wird.

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class ScannerExample {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (true){
            String s = scanner.next();
            if(s.equals("q")) break;
            System.out.println(s);
        }
        System.out.println("Bye...");
        scanner.close();
    }
}

Das zweite Beispiel zeigt wie Scanner aus einer Textdatei liest und dabei zwischen numerischen und nicht numerischen Werten unterscheiden kann.
Hierzu muss dem Scanner-Objekt ein File-Objekt übergeben werden. Es erhält seinerseits den Pfad zur Datei als String. Als zweiter, optionaler Parameter kann dem Konstruktor ein String des Zeichensatzes der Datei übergeben werden.

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Locale;
import java.util.Scanner;

public class ScannerExample {

    public static void main(String[] args) {
        Scanner scanner;
        try {
            scanner = new Scanner(new File("test.txt"),
                    "UTF-8");
            scanner.useLocale(Locale.GERMANY);
            int i;
            double d;
            while (scanner.hasNext()) {
                if (scanner.hasNextInt()) {
                    i = scanner.nextInt();
                    System.out.println("Int: " + ++i);
                }else if (scanner.hasNextDouble()) {
                    d = scanner.nextDouble();
                    System.out.println("Double: " + ++d);
                } else {
                    System.out.println("String: " + scanner.next());
                }
            }
            scanner.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}

Scanner deklariert die Methode hasNext(). Sie liefert so lange true wie weitere Elemente ausgelesen werden können. Somit lässt sie sich als Abbruchbedingung in einer while-Schleife einsetzen, in der der Inhalt der Datei elementweise ausgegeben wird.
'Elemente' sind in der Standardeinstellung durch Leerzeichen voneinander getrennte lesbare Strukturen, bei konventionellen Texten somit die einzelnen Wörter. Die Leerzeichen selbst werden jedoch nicht mit zurückgegeben.

Die Klasse Scanner kennt eine ganze Reihe teilweise überladener hasNextXX()- und nextXX()-Methoden. XX bezeichnet hier Platzhalter für verschiedene Datentypen, auf die die Methoden prüfen können. Die Methoden hasNextXX() liefern, wie oben demonstriert, boolsche Werte, die im Beispiel als Filter eingesetzt werden. Die Methode hasNextInt() prüft hierbei auf mögliche Integer-Werte, die durch nextInt() ermittelt, hier inkrementiert und dann ausgegeben werden. Ähnlich verhält es sich mit hasNextDouble(). Trifft keine der beiden Bedingungen zu, so wird das Element als String behandelt.

Enthält die ausgelesene Datei den folgenden Eintrag

1 071 1.23 Dies 0xF3 ist 1,4 ein Test

so zeigt das Ergebnis:

Int: 2
Int: 72
String: 1.23
String: Dies
String: 0xF3
String: ist
Double: 2.4
String: ein
String: Test

Hieran lässt sich zweierlei gut erkennen:

  1. Andere als dezimale Integer-Werte werden nicht automatisch als solche erkannt. Dies kann auch nicht innerhalb der Methoden hasNextInt(int radix) und nextInt(int radix) durch die Angabe von radix erreicht werden, da die Methoden lediglich die bereits erkannten Integer entsprechend bewerten, auf die Erkennung selbst jedoch keinen Einfluss haben.
  2. Bei der Behandlung von Integer-Werten wird ohne gesonderte Angabe von radix von der Basis 10 ausgegangen. Das Literal 071 wird trotz der führenden 0 nicht oktal sondern dezimal interpretiert.

Ein Scanner-Objekt besitzt eine Lokalisierungs-Eigenschaft, die die zugrunde liegende Behandlung von regulären Ausdrücken erheblich beeinflusst. Man erkennt dies im Beispiel an der Interpretation des ersten, mit einem Punkt als Dezimaltrenner geschriebenen Dezimalwertes, der hier als String interpretiert wird und dem zweiten, mit Komma geschriebenen Dezimalwert, der hier im deutschen Umfeld als double erfasst wird.

Die Lokalisierung des Scanner-Objekts richtet sich in den Standard-Einstellungen nach der Laufzeitumgebung. Sie kann jedoch auch explizit gesetzt werden, wie es hier in der Zeile

scanner.useLocale(Locale.GERMANY);

demonstriert wird.

Das Leerzeichen als standardmäßig verwendeter Elementtrenner kann durch die Methode useDelimiter() nach Bedarf angepasst werden. Es wird an einem Beispiel demonstriert, in dem hier ein hart codiertes String-Objekt eingelesen wird.

String in = "eins#zwei#drei#vier";
Scanner scan = new Scanner(in).useDelimiter("#");
while(scan.hasNext()) {
    System.out.println(scan.next());
}
scan.close();

Die Ausgabe liefert

eins
zwei
drei
vier