Du liest:
Java Scanner: Inputs in Java (mit Codebeispielen)

Java Scanner: Inputs in Java (mit Codebeispielen)

von Pero
20.06.2020
Die Java Scanner Klasse

Die Ein- und Ausgabe, kurz I/O (engl. Input/Output), ist ein wichtiger Bestandteil eines jeden Betriebssystem und einer jeden Programmiersprache. Ein Programm, das keine Ein- und/oder Ausgabe hat, ist für uns meistens relativ uninteressant (kann allen Theoretikern natürlich trotzdem gefallen). Die Verwendung von I/O stellt sich jedoch schnell als eines der interessantesten Gebiete der Programmierung heraus. Die Verarbeitung von I/O passiert zwar meist im Hintergrund, begleitet uns allerdings trotzdem tagtäglich. Trotzdem scheuen sich viele Entwickler vor diesem Gebiet. I/O-Kenntnisse sind allerdings für jeden Java-Entwickler unabdingbar. Um Programme zu erstellen, die nicht nur einem völlig trivialen, also einem gradlinigen, Programmablauf folgen, müssen wir uns zunächst damit beschäftigen, wie wir Daten aus Dateien lesen können (Eingabe) und wie wir entsprechende Daten auch wieder in Dateien auslagern bzw. schreiben können. In diesem Artikel betrachten wir deshalb die Java Scanner-Klasse und wie wir sie zum einlesen von Informationen aus Dateien nutzen können.

Bis zur Version 1.5 (Tiger) von Java, waren wir immer von den Zeichen- und Byte-Stream-Klassen aus der java.io abhängig; in Tiger wurde dann die Scanner-Klasse eingeführt. Wir können diese Klasse aus dem java.util-Paket importieren.

Der Scanner wird zum Lesen von Daten verwendet, sodass wir diese im Programm verwenden können. Der Scanner kann aus einem Eingangsfluss (InputStream), einer Datei, einem String und aus einem Pfad, Daten entnehmen und diese dem fortlaufenden Programm zur Verfügung stellen.

Mit dem Java Scanner Dateien einlesen

Wir können dem Scanner wie folgt eine Instanz zu einem Datei-Objekt übergeben.

Scanner scanner = new Scanner(new File("hallo.txt"));

Dafür müssen wir sicherstellen, dass wir java.util.Scanner und java.io.File importiert haben.

Aus einem Eingangsfluss (InputStream) einlesen

Du kannst auch die Instanz eines Eingangsfluss (InputStream) an den Konstruktor der Klasse übergeben. Im folgenden Beispiel können wir sehen, wie das möglich ist. Dabei müssen wir darauf achten, dass wir java.io.InputStream importiert haben.

ClassLoader cl = getClass().getClassLoader();
InputStream eingangsstrom = cl.getResourceAsStream("hallo.txt");
Scanner scanner = new Scanner(eingangsstrom)

Der obige Quellcode eignet sich, wenn die Datei, aus der wir einlesen möchten, sich im Java-Klassenpfad (Arbeitpfad) befindet. Ist dies nicht der Fall, kannst du auch wie folgt vorgehen.

Class klasse = getClass();
InputStream eingangsfluss = klasse.getResourcesAsStream("hallo.txt");
Scanner scanner = new Scanner(eingangsfluss);

Das Scanner-Objekt kann die primitiven Datentypen (byte, short, int, long, float, double, boolean, char) und natürlich auch Strings lesen.

Um den Inhalt einer Datei zu lesen, können wir Folgendes implementieren.

Scanner scanner;
    try {

      StringBuffer sb = new StringBuffer();
      String aktueller_pfad = System.getProperty("user.dir");
      String dateiname = String.format("%s/%s", aktueller_pfad, dateiname);

      logger.log(Level.INFO, dateiname);

      scanner = new Scanner(new File(dateiname));

      while(scanner.hasNext()) {.         // (1)
        sb.append(scanner.nextLine());    // (2)
      }
      System.out.println(new String(sb));
      scanner.close();                    // (3)
    }
    catch(Exception ffe) {
      logger.log(Level.SEVERE, ffe.getMessage());
    }

1) Die Methode hasNext() des Scanners gibt true zurück, wenn die aktuelle Zeile nicht die letzte Zeile in der Datei ist. So können wir relativ einfach überprüfen, ob wir am Ende der Datei angekommen sind.

(2) Die Methode nextLine() gibt ein String-Objekt zurück, das den Inhalt der aktuellen Zeile beinhaltet. Wenn wir diese Methode das nächste Mal aufrufen, liest sie diese Zeile und rückt eine Zeile weiter. Diese Methode sucht nach der Zeilenbegrenzung, die du vermutlich am ehesten mit „\n“ assoziieren kannst. Wenn sich in der Zeile keine Begrenzung befindet, kann es passieren, dass die gesamte Datei bzw. alle Daten bis zur nächsten Begrenzung eingelesen werden.

(3) Nach Gebrauch des Scanner-Objekts dürfen wir nicht vergessen, dieses auch wieder zu schließen. Dabei müssen wir dann aber auch beachten, dass wir nach dem Aufruf von close() keine weiteren Aufrufe mit dem Scanner-Objekt machen. Jeder Aufruf eines bereits geschlossenen Scanner-Objekts führt zu einem IllegalStateException-Fehler.

Nutzung der Java Scanner next() Methode

try (Scanner scanner = new Scanner("Scanner\n")) {
  scanner.useDelimiter("");
  String ergebnis = scanner.next();
  System.out.println(ergebnis); // gibt „S" aus
}

Im obigen Beispiel können wir sehen, dass durch den Aufruf der Methode next() ein “S” ausgegeben wird und die Scannerposition auf “c” vorrückt.

Allerdings müssen wir im Beispiel nicht wie vorher erwähnt, die close() Methode aufrufen, da wir mit dem try-with-resources-Block arbeiten. Dieser schließt nach seinem Durchlauf das Objekt automatisch.

Nutzereingabe per Konsole und Tastatur

Der Scanner kann auch Daten aus System.in einlesen. System.in ist normalerweise an die Eingabe in der Konsole mit der Tastatur geknüpft. Wie bei den anderen Möglichkeiten zuvor, können wir auch hier die System.in an den Konstruktor des Scanners übergeben. Das sieht dann wie folgt aus:

Scanner scanner = new Scanner(System.in);

Danach kannst du alle Arten von Daten mithilfe des Scanner-Objekts einlesen. Um zum Beispiel ein String-Objekt einzulesen, schreibst du folgendes:

scanner.next();

Um eine ganze Zahl (Integer) einzulesen:

scanner.nextInt();

Und um eine Kommazahl (Float) einzulesen, must du Folgendes eingeben:

scanner.nextFloat();

Es gibt eine ganze Reihe von den nextXXX()-Methoden in der Scanner-Klasse.

Betrachten wir jetzt ein nahezu vollständiges Beispiel, wie wir die Scanner-Klasse nutzen können, um die Eingaben des Benutzers auf der Tastatur zu lesen.

class EingabeBeispiel {

  void run() throws Exception {

    Scanner scanner = new Scanner(System.in);

    System.out.println("Geben Sie Ihren Namen ein:");
    String name = scanner.next();
    System.out.println("Geben Sie auch Ihren Geburtstag ein (tt-mm-jjj):");
    String geburtstag = scanner.next();

    Date datum = new SimpleDateFormat("tt-mm-jjj ").parse(geburtstag);
    LocalDate lokales_datum = datum.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    // berechne Alter
    Period periode = Period.between(lokalesDatum, lokales_datum.now());
    String alter = String.format("%d Jahre %d Monate und %d Tage alt", 
                         periode.getYears(), periode.getMonths(), periode.getDays());
    String nachricht = String.format("Hallo %s, du bist jetzt %s", name, alter);

    System.out.println(nachricht);

    scanner.close();

  }
}

Standort/Sprache einstellen

Du kannst außerdem den Standort/die Sprache des Scanners ändern, indem du die Methode useLocal() verwendest:

class Beispiel {
  void run() {

    System.out.printf("Java nutz aktuell folgende Sprache: %s\n", Locale.getDefault());

    Scanner scanner = new Scanner(""); // (1)
    System.out.printf("Der Scanner nutzt gerade folgende Sprache: %s\n", scanner.locale()); // (2)

    scanner.useLocale(Locale.ENGLISH); // (3)
    System.out.printf("Der Scanner nutzt gerade folgende Sprache: %s\n", scanner.locale()); // (4)

    scanner.close();

  }
}

(1) Wir übergeben dem Konstruktor des Scanners nur einen leeren String, da für uns das Einlesen gerade nicht relevant ist. Wir müssen einen leeren String übergeben, da der Konstruktor immer mindestens einen Parameter verlangt.

(2) Gibt die aktuelle Sprache aus, die zur Laufzeit von Java erkannt wurde.

(3) Diese Zeile bzw. Befehl setzt die Sprache des Scanners auf Englisch.

(4) Nun wird “en” Abkürzung für Englisch ausgegeben.

Ein frei wählbares Begrenzungszeichen setzen

In der Standardeinstellung nutzt der Scanner das Leerzeichen (Leertaste) als Grenze für jede der bereits kennengelernten next()-Methoden. Allerdings können wir dieses Zeichen auch gegen ein von uns ausgesuchtes Zeichen auswechseln.

class ausgesuchteBegrenzung {
  void run() {
    Scanner scanner = new Scanner("A:B:C:D");

    while(scanner.hasNext()) {
      System.out.println(scanner.next()); 
    }
    scanner.close();
  }
}

Der obige Quellcode gibt “A:B:C:D” aus. Der Grund dafür liegt fast schon auf der Hand. Wir haben gesagt, das die next()-Methode nach dem nächsten Leerzeichen sucht. In der von uns eingegeben Zeile befindet sich allerdings kein Leerzeichen. Deswegen wurde einfach die ganze Zeile in Einem ausgegeben.

Um jetzt den Doppelpunkt als Begrenzungszeichen festzulegen, können wir die Methode useDelimiter() verwenden:

class ausgesuchteBegrenzung {
  void run() {
    Scanner scanner = new Scanner("A:B:C:D");

    scanner.useDelimiter(":");

    while(scanner.hasNext()) {
      System.out.println(scanner.next());
    }
    scanner.close();
  }
}

Die useDelimiter()-Methode nimmt den angegeben String und setzt ihn als neues Begrenzungszeichen. Neben einem einzigen Zeichen können wir auch eine Kombination aus Mehreren verwenden. Hier haben wir in kleines Beispiel:

String input = "1 Fisch 2 Fisch roter Fisch blauer Fisch";

Scanner s = new Scanner(input).useDelimiter("\\s*Fisch\\s*");
System.out.println(s.nextInt());
System.out.println(s.nextInt());
System.out.println(s.next());
System.out.println(s.next());
s.close();

Das Beispiel stammt aus der offiziellen Dokumentation der Scanner-Klasse auf oracle.com

Zusammenfassung der Java Scanner Klasse

Die Java Scanner-Klasse lässt sich von uns vielseitig einsetzen, um aus verschiedenen Quellen Daten einzulesen. Wir können aus seiner Datei, einem Eingangsfluss (InputStream), einem Pfad oder auch ganz einfach aus einem String Daten auslesen. Sollten wir bei der Entwicklung von Programmen also einmal auf das Problem stoßen, dass eine Eingabe des Benutzers notwendig ist, können wir dafür die Scanner-Klasse verwenden. Wir haben auch gelernt, dass wir mittels der nextXXX()-Methode zahlreiche verschiedene Datentypen einlesen können.



Bislang gibt es keine Kommentare. Markier dein Revier und sei der Erste!

Schreibe einen Kommentar

Das könnte dich auch interessieren