{"id":8371,"date":"2019-11-21T09:00:00","date_gmt":"2019-11-21T08:00:00","guid":{"rendered":"https:\/\/www.happycoders.eu\/?p=8371"},"modified":"2024-11-29T15:47:25","modified_gmt":"2024-11-29T14:47:25","slug":"dateien-einfach-schnell-lesen","status":"publish","type":"post","link":"https:\/\/www.happycoders.eu\/de\/java\/dateien-einfach-schnell-lesen\/","title":{"rendered":"Dateien schnell und einfach lesen (Java Datei Tutorial)"},"content":{"rendered":"\n<p>F\u00fcr das Lesen und Schreiben von Dateien in Java gibt es in den Packages <code>java.io<\/code> und <code>java.nio.file<\/code> zahlreiche Klassen. Seit der Einf\u00fchrung der Java NIO.2 (New I\/O) File API verliert man \u2013 nicht nur als Einsteiger \u2013 leicht den \u00dcberblick. Viele Datei-Operationen lassen sich seither auf mehrere Arten durchf\u00fchren.<\/p>\n\n\n\n<p>Diese Artikelserie stellt zuerst einfache Utility-Methoden vor, um Dateien zu lesen und zu schreiben. In sp\u00e4teren Teilen werden komplexere und fortgeschrittene Methoden behandelt: \u00fcber Channels und Buffers bis hin zu Memory-Mapped I\/O (es macht nichts, wenn dir das an dieser Stelle noch nichts sagt).<\/p>\n\n\n\n<p>Der erste Artikel behandelt das Lesen von Dateien. Du lernst zun\u00e4chst, wie man Dateien einliest, die komplett in den Arbeitsspeicher passen:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Wie liest man am einfachsten eine Textdatei in einen String (oder eine String-Liste)?<\/li>\n\n\n\n<li>Wie liest man eine Bin\u00e4rdatei in ein Byte-Array?<\/li>\n<\/ul>\n\n\n\n<p>Danach geht es weiter zu gr\u00f6\u00dferen Dateien und den daf\u00fcr zust\u00e4ndigen Klassen:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Wie liest man gr\u00f6\u00dfere Dateien und verarbeitet sie gleichzeitig weiter (um nicht die komplette Datei im Speicher halten zu m\u00fcssen)?<\/li>\n\n\n\n<li>Wann verwendet man <code>FileReader<\/code>, <code>FileInputStream<\/code>, <code>InputStreamReader<\/code>, <code>BufferedInputStream<\/code> und <code>BufferedReader<\/code>?<\/li>\n\n\n\n<li>Wann verwendet man <code>Files.newInputStream()<\/code> und <code>Files.newBufferedReader()<\/code>?<\/li>\n<\/ul>\n\n\n\n<p>Au\u00dferdem (und das gilt sowohl f\u00fcr kleine als auch f\u00fcr gro\u00dfe Dateien):<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Was muss man beachten, damit der Dateizugriff auf jedem Betriebssystem funktioniert?<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"wie-liest-man-in-java-am-einfachsten-eine-datei\">Wie liest man in Java am einfachsten eine Datei?<\/h2>\n\n\n\n<p>Bis einschlie\u00dflich Java 6 musste man f\u00fcr das Lesen einer Datei mehrere Zeilen Programmcode um einen <code>FileInputStream<\/code> herum schreiben. Dabei musste man darauf achten, dass man diesen nach dem Lesen \u2013 und auch im Fehlerfall \u2013 wieder korrekt schlie\u00dft. \"Try-with-resources\" (also das automatische Schlie\u00dfen aller im <code>try<\/code>-Block ge\u00f6ffneten Resourcen) gab es damals noch nicht.<\/p>\n\n\n\n<p>Nur \u00fcber Drittanbieter-Libraries (z. B. <a rel=\"noopener\" href=\"https:\/\/commons.apache.org\/\" target=\"_blank\">Apache Commons<\/a> oder <a rel=\"noopener\" href=\"https:\/\/guava.dev\/\" target=\"_blank\">Guava<\/a>) konnte man auf komfortablere M\u00f6glichkeiten zur\u00fcckgreifen.<\/p>\n\n\n\n<p>Mit Java 7 kam dann die \u00fcber das <a rel=\"noopener\" href=\"https:\/\/jcp.org\/en\/jsr\/detail?id=203\" target=\"_blank\">JSR 203<\/a> die langersehnte \"NIO.2 File API\" (NIO steht f\u00fcr New I\/O). Mit der neuen API kam unter anderem die Utility-Klasse <code>java.nio.file.Files<\/code>, \u00fcber die du mit einem einzigen Methoden-Aufruf Text- sowie Bin\u00e4rdateien komplett einlesen kannst.<\/p>\n\n\n\n<p>Welche Methoden das im Detail sind, erf\u00e4hrst du in den folgenden Abschnitten.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"laden-einer-binaerdatei-in-ein-byte-array\">Laden einer Bin\u00e4rdatei in ein Byte-Array<\/h3>\n\n\n\n<p>Du kannst den kompletten Inhalt einer Datei \u00fcber die Methode <code>Files.readAllBytes()<\/code> in ein Byte-Array einlesen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">String fileName = ...;\n<span class=\"hljs-keyword\">byte<\/span>&#091;] bytes = Files.readAllBytes(Path.of(fileName));<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Die Klasse <code>Path<\/code> ist dabei eine Abstraktion von Datei- und Verzeichnisnamen, deren Details hier erstmal nicht relevant sind. Auf diese gehe ich in einem sp\u00e4teren Artikel n\u00e4her ein. Zun\u00e4chst gen\u00fcgt es zu wissen, dass du ein <code>Path<\/code>-Objekt \u00fcber <code>Paths.get()<\/code> oder \u2013 seit <a href=\"\/de\/java\/java-11-features\/#Pathof\">Java 11<\/a> etwas eleganter \u2013 \u00fcber <code>Path.of()<\/code> erstellen kannst.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"laden-einer-textdatei-in-einen-string\">Laden einer Textdatei in einen String<\/h3>\n\n\n\n<p>M\u00f6chtest du den Inhalt einer Textdatei in einen String laden, geht das \u2013 seit Java 11 \u2013 \u00fcber die Methode <code>Files.readString()<\/code> wie folgt:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">String fileName = ...;\nString text = Files.readString(Path.of(fileName));<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Die Methode <code>readString()<\/code> ruft dabei intern wiederum <code>readAllBytes()<\/code> auf und wandelt danach die Bin\u00e4rdaten in die gew\u00fcnschte Zeichenkette um.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"zeilenweises-laden-einer-textdatei-in-eine-string-liste\">Zeilenweises Laden einer Textdatei in eine String-Liste<\/h3>\n\n\n\n<p>Der Inhalt von Textdateien ist in den allermeisten F\u00e4llen auf mehrere Zeilen verteilt. M\u00f6chtest du den Text zeilenweise verarbeiten, brauchst du dir nicht selbst die M\u00fche zu machen, den eingelesenen Text aufzusplitten. Dies kann direkt beim Laden erfolgen, in dem du die \u2013 seit Java 8 verf\u00fcgbare \u2013 Methode <code>readAllLines()<\/code> verwendest:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">String fileName = ...;\nList&lt;String&gt; lines = Files.readAllLines(Path.of(fileName));<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Danach kannst du leicht \u00fcber die erhaltene String-Liste iterieren und diese weiterverarbeiten.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"zeilenweises-laden-einer-textdatei-in-einen-string-stream\">Zeilenweises Laden einer Textdatei in einen String-Stream<\/h3>\n\n\n\n<p>In Java 8 wurden Streams eingef\u00fchrt. Entsprechend wurde in derselben Java-Version die Klasse <code>Files<\/code> um die Methode <code>lines()<\/code> erweitert, die die Zeilen einer Textdatei nicht als String-Liste zur\u00fcckzuliefert, sondern als Stream von Strings:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">String fileName = ...;\nStream&lt;String&gt; lines = Files.lines(Path.of(fileName));<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>So k\u00f6nntest du beispielsweise mit nur einem Code-Statement alle Zeilen einer Textdatei ausgeben, die die Zeichenkette \"foo\" enthalten:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">Files.lines(Path.of(fileName))\n      .filter(line -&gt; line.contains(<span class=\"hljs-string\">\"foo\"<\/span>))\n      .forEach(System.out::println);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"java-nio-file-files-zusammenfassung\">java.nio.file.Files \u2013 Zusammenfassung<\/h3>\n\n\n\n<p>Mit den vier gezeigten Methoden lassen sich viele Anwendungsf\u00e4lle abdecken. Allerdings sollten die gelesenen Dateien nicht zu gro\u00df sein, da diese komplett in den Arbeitsspeicher geladen werden. Mit einem HD-Film solltest du das also nicht versuchen. Doch auch f\u00fcr kleinere Dateien gibt es gute Gr\u00fcnde diese nicht komplett in den RAM zu laden:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Eventuell m\u00f6chte man die gelesenen Daten so schnell wie m\u00f6glich weiterverarbeiten, und zwar bevor die Datei komplett geladen wurde.<\/li>\n\n\n\n<li>L\u00e4uft deine Software in Containern oder als \"Function-as-a-Service\", k\u00f6nnte Arbeitsspeicher u. U. relativ teuer sein.<\/li>\n<\/ul>\n\n\n\n<p>Wie du Dateien St\u00fcck f\u00fcr St\u00fcck einlesen und dabei direkt verarbeiten kannst, wird im folgenden Kapitel beschrieben.<\/p>\n\n\n<div class=\"convertkit-form wp-block-convertkit-form\" style=\"\"><script async data-uid=\"1427197203\" src=\"https:\/\/happycoders.kit.com\/1427197203\/index.js\" data-jetpack-boost=\"ignore\" data-no-defer=\"1\" data-no-optimize=\"1\" nowprocket><\/script><\/div>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"wie-verarbeitet-man-grosse-dateien-ohne-sie-komplett-im-arbeitsspeicher-halten-zu-muessen\">Wie verarbeitet man gro\u00dfe Dateien, ohne sie komplett im Arbeitsspeicher halten zu m\u00fcssen?<\/h2>\n\n\n\n<p>Und damit kommen wir zu den Funktionen, die schon vor Java 7 verf\u00fcgbar waren \u2013 also diejenigen, die das \"mal eben einlesen\" einer kleinen Datei zu einer komplizierten Angelegenheit gemacht haben.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"lesen-grosser-binaerdateien-mit-fileinputstream\">Lesen gro\u00dfer Bin\u00e4rdateien mit FileInputStream<\/h3>\n\n\n\n<p>Im einfachsten Fall lesen wir eine Bin\u00e4rdatei Byte f\u00fcr Byte und verarbeiten diese Bytes weiter. Diese Aufgabe erledigt die Klasse <code>FileInputStream<\/code>. Im folgenden Beispiel wird sie verwendet, um den Inhalt einer Datei Byte f\u00fcr Byte auf der Konsole auszugeben.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">String fileName = ... ;\n<span class=\"hljs-keyword\">try<\/span> (FileInputStream is = <span class=\"hljs-keyword\">new<\/span> FileInputStream(fileName)) {\n  <span class=\"hljs-keyword\">int<\/span> b;\n  <span class=\"hljs-keyword\">while<\/span> ((b = is.read()) != -<span class=\"hljs-number\">1<\/span>) {\n    System.out.println(<span class=\"hljs-string\">\"Byte: \"<\/span> + b);\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Die Methode <code>FileInputStream.read()<\/code> liest dabei jeweils ein Byte aus der Datei. Ist das Ende der Datei erreicht, wird -1 zur\u00fcckgegeben. Die Funktionalit\u00e4t dieser Klasse ist zum gr\u00f6\u00dften Teil nativ (also nicht in Java) implementiert, da sie direkt auf die I\/O-Funktionalit\u00e4t des Betriebssystem zugreift. <\/p>\n\n\n\n<p>Dieser Zugriff ist relativ teuer: Das Laden einer <a rel=\"noopener\" href=\"http:\/\/mattmahoney.net\/dc\/textdata.html\" target=\"_blank\">100 Millionen Byte gro\u00dfen Testdatei<\/a> \u00fcber einen <code>FileInputStream<\/code> dauert auf meinem System knapp 190 Sekunden. Das sind nur etwa 0,5 MB pro Sekunde.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"lesen-grosser-binaerdateien-mit-dem-nio-2-inputstream\">Lesen gro\u00dfer Bin\u00e4rdateien mit dem NIO.2 InputStream<\/h3>\n\n\n\n<p>Mit der NIO.2 File API in Java 7 kam mit <code>Files.newInputStream()<\/code> eine zweite Methode hinzu, um einen <code>InputStream<\/code> zu erzeugen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">String fileName = ...;\n<span class=\"hljs-keyword\">try<\/span> (InputStream is = Files.newInputStream(Path.of(fileName))) {\n  <span class=\"hljs-keyword\">int<\/span> b;\n  <span class=\"hljs-keyword\">while<\/span> ((b = is.read()) != -<span class=\"hljs-number\">1<\/span>) {\n    System.out.println(<span class=\"hljs-string\">\"Byte: \"<\/span> + b);\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Diese Methode liefert einen <code>ChannelInputStream<\/code> anstatt eines <code>FileInputStreams<\/code>, da NIO.2 unter der Haube mit sogenannten Channels arbeitet. An der Geschwindigkeit \u00e4ndert sich dadurch in meinen Tests nichts.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"schneller-lesen-mit-dem-bufferedinputstream\">Schneller lesen mit dem BufferedInputStream<\/h3>\n\n\n\n<p>Beschleunigt werden kann der Zugriff mit dem <code>BufferedInputStream<\/code>. Dieser wird sozusagen um den <code>FileInputStream<\/code> gelegt und l\u00e4dt die Daten vom Betriebssystem nicht Byte f\u00fcr Byte, sondern in Bl\u00f6cken von standardm\u00e4\u00dfig 8 KB und speichert diese zwischen. Die Bytes k\u00f6nnen dann wiederum nach und nach ausgelesen werden. Dieses mal aber aus dem Arbeitsspeicher, was um ein Vielfaches schneller geht.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">String fileName = ...;\n<span class=\"hljs-keyword\">try<\/span> (FileInputStream is = <span class=\"hljs-keyword\">new<\/span> FileInputStream(fileName);\n     BufferedInputStream bis = <span class=\"hljs-keyword\">new<\/span> BufferedInputStream(is)) {\n  <span class=\"hljs-keyword\">int<\/span> b;\n  <span class=\"hljs-keyword\">while<\/span> ((b = bis.read()) != -<span class=\"hljs-number\">1<\/span>) {\n    System.out.println(<span class=\"hljs-string\">\"Byte: \"<\/span> + b);\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Dieselbe Datei wird durch diesen Code in nur 270 ms eingelesen, also um den Faktor 700 schneller. Das sind 370 MB pro Sekunde, ein hervorragender Wert.<\/p>\n\n\n\n<p>Man sollte also fast immer einen <code>BufferedInputStream<\/code> verwenden. Die einzige Ausnahme ist, wenn man die Daten \u00fcber den <code>FileInputStream<\/code> nicht Byte f\u00fcr Byte liest, sondern in gr\u00f6\u00dferen Bl\u00f6cken, deren Gr\u00f6\u00dfe m\u00f6glichst an die Blockgr\u00f6\u00dfe des Dateisystems angepasst ist. Wenn du dir unsicher bist, ob sich der <code>BufferedInputStream<\/code> f\u00fcr deinen speziellen Einsatzbereich lohnt, dann probier es einfach aus.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"lesen-grosser-textdateien-mit-dem-filereader\">Lesen gro\u00dfer Textdateien mit dem FileReader<\/h3>\n\n\n\n<p>Textdateien sind letztendlich auch Bin\u00e4rdateien. Beim Laden werden Bytes in Zeichen umgewandelt. Diese Aufgabe \u00fcbernimmt die Klasse <code>InputStreamReader<\/code>. Wenn du diese um einen <code>FileInputStream<\/code> legst, kannst du anstelle von Bytes Zeichen lesen und ausgeben:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">String fileName = ...;\n<span class=\"hljs-keyword\">try<\/span> (FileInputStream is = <span class=\"hljs-keyword\">new<\/span> FileInputStream(fileName);\n     InputStreamReader reader = <span class=\"hljs-keyword\">new<\/span> InputStreamReader(is)) {\n  <span class=\"hljs-keyword\">int<\/span> c;\n  <span class=\"hljs-keyword\">while<\/span> ((c = reader.read()) != -<span class=\"hljs-number\">1<\/span>) {\n    System.out.println(<span class=\"hljs-string\">\"Char: \"<\/span> + (<span class=\"hljs-keyword\">char<\/span>) c);\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Etwas komfortabler geht es mit dem <code>FileReader<\/code>: Dieser kombiniert <code>FileInputStream<\/code> und <code>InputStreamReader<\/code>, so dass folgender Code entsteht, der \u00e4quivalent ist zu dem oben:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">String fileName = ...;\n<span class=\"hljs-keyword\">try<\/span> (FileReader reader = <span class=\"hljs-keyword\">new<\/span> FileReader(fileName)) {\n  <span class=\"hljs-keyword\">int<\/span> c;\n  <span class=\"hljs-keyword\">while<\/span> ((c = reader.read()) != -<span class=\"hljs-number\">1<\/span>) {\n    System.out.println(<span class=\"hljs-string\">\"Char: \"<\/span> + (<span class=\"hljs-keyword\">char<\/span>) c);\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Der <code>InputStreamReader<\/code> verwendet intern ebenfalls einen 8 KB-Puffer. Das Einlesen der 100 Millionen Byte gro\u00dfen Textdatei dauert Zeichen f\u00fcr Zeichen etwa 3,8 s.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"textdateien-schneller-lesen-mit-dem-bufferedreader\">Textdateien schneller lesen mit dem BufferedReader<\/h3>\n\n\n\n<p>Obwohl der <code>InputStreamReader<\/code> schon ziemich schnell ist, kann das Einlesen von Texten noch weiter beschleunigt werden \u2013 mit dem <code>BufferedReader<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">String fileName = ...;\n<span class=\"hljs-keyword\">try<\/span> (FileReader reader = <span class=\"hljs-keyword\">new<\/span> FileReader(fileName);\n     BufferedReader bufferedReader = <span class=\"hljs-keyword\">new<\/span> BufferedReader((reader))) {\n  <span class=\"hljs-keyword\">int<\/span> c;\n  <span class=\"hljs-keyword\">while<\/span> ((c = bufferedReader.read()) != -<span class=\"hljs-number\">1<\/span>) {\n    System.out.println(<span class=\"hljs-string\">\"Char: \"<\/span> + (<span class=\"hljs-keyword\">char<\/span>) c);\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Dadurch wird die Zeit f\u00fcr das Einlesen der Testdatei auf etwa 1,3 s reduziert. Dies erreicht der <code>BufferedReader<\/code>, indem er dem 8 KB-Puffer des <code>InputStreamReaders<\/code> noch einen Puffer f\u00fcr dekodierte 8192 Zeichen zur Seite stellt.<\/p>\n\n\n\n<p>Ein weiterer Vorteil des <code>BufferedReader<\/code> ist, dass dieser die zus\u00e4tzliche Methode <code>readLine()<\/code> anbietet, mit der du die Textdatei nicht nur Zeichen f\u00fcr Zeichen, sondern auch Zeile f\u00fcr Zeile einlesen und verarbeiten kannst:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">String fileName = ...;\n<span class=\"hljs-keyword\">try<\/span> (FileReader reader = <span class=\"hljs-keyword\">new<\/span> FileReader(fileName);\n     BufferedReader bufferedReader = <span class=\"hljs-keyword\">new<\/span> BufferedReader((reader))) {\n  String line;\n  <span class=\"hljs-keyword\">while<\/span> ((line = bufferedReader.readLine()) != <span class=\"hljs-keyword\">null<\/span>) {\n    System.out.println(<span class=\"hljs-string\">\"Line: \"<\/span> + line);\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Das Einlesen kompletter Zeilen reduziert die Gesamtzeit f\u00fcr das Einlesen der Testdatei weiter auf etwa 600 ms.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"textdateien-schneller-lesen-mit-dem-nio-2-bufferedreader\">Textdateien schneller lesen mit dem NIO.2 BufferedReader<\/h3>\n\n\n\n<p>Die NIO.2 File API bietet mit <code>Files.newBufferedReader()<\/code> eine Methode, um direkt einen <code>BufferedReader<\/code> zu erzeugen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">String fileName = ...;\n<span class=\"hljs-keyword\">try<\/span> (BufferedReader reader = Files.newBufferedReader(Path.of(fileName))) {\n  <span class=\"hljs-keyword\">int<\/span> c;\n  <span class=\"hljs-keyword\">while<\/span> ((c = reader.read()) != -<span class=\"hljs-number\">1<\/span>) {\n    System.out.println(<span class=\"hljs-string\">\"Char: \"<\/span> + (<span class=\"hljs-keyword\">char<\/span>) c);\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Dieser entspricht von der Geschwindigkeit dem \"klassisch\" erstellten <code>BufferedReader<\/code> und ben\u00f6tigt wie dieser etwa 1,3 Sekunden, um die gesamte Datei einzulesen.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"uebersicht-performance\">\u00dcbersicht Performance<\/h3>\n\n\n\n<p>Das folgende Diagramm zeigt noch einmal alle vorgestellten Methoden und die Zeit, die diese jeweils f\u00fcr das Einlesen einer 100 Millionen Byte gro\u00dfen Datei ben\u00f6tigen:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img decoding=\"async\" width=\"659\" height=\"600\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/Reading-files-in-Java-performance-comparison.png\" alt=\"Vergleich der Zeiten zum Einlesen einer 100 Millionen Byte gro\u00dfen Datei in Java\" class=\"wp-image-8601\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/Reading-files-in-Java-performance-comparison.png 659w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/Reading-files-in-Java-performance-comparison-224x204.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/Reading-files-in-Java-performance-comparison-336x306.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/Reading-files-in-Java-performance-comparison-504x459.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/Reading-files-in-Java-performance-comparison-400x364.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/Reading-files-in-Java-performance-comparison-600x546.png 600w\" sizes=\"(max-width: 659px) 100vw, 659px\" \/><figcaption class=\"wp-element-caption\">Vergleich der Zeiten zum Einlesen einer 100 Millionen Byte gro\u00dfen Datei in Java<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Der gro\u00dfe Abstand zwischen \"unbuffered\" und \"buffered\" f\u00fchrt dazu, dass die \"buffered\" Methoden im Diagramm oben kaum erkennbar sind. Daher hier ein zweites Diagramm, das nur die \"buffered\" Methoden darstellt:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img decoding=\"async\" width=\"602\" height=\"507\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/Reading-files-in-Java-performance-comparison-buffered.png\" alt=\"Vergleich der Zeiten zum Einlesen einer 100 Millionen Byte gro\u00dfen Datei in Java (buffered)\" class=\"wp-image-8603\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/Reading-files-in-Java-performance-comparison-buffered.png 602w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/Reading-files-in-Java-performance-comparison-buffered-224x189.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/Reading-files-in-Java-performance-comparison-buffered-336x283.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/Reading-files-in-Java-performance-comparison-buffered-504x424.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/Reading-files-in-Java-performance-comparison-buffered-400x337.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/Reading-files-in-Java-performance-comparison-buffered-600x505.png 600w\" sizes=\"(max-width: 602px) 100vw, 602px\" \/><figcaption class=\"wp-element-caption\">Vergleich der Zeiten zum Einlesen einer 100 Millionen Byte gro\u00dfen Datei in Java (buffered)<\/figcaption><\/figure>\n<\/div>\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"uebersicht-fileinputstream-filereader-inputstreamreader-bufferedinputstream-bufferedreader\">\u00dcbersicht FileInputStream, FileReader, InputStreamReader, BufferedInputStream, BufferedReader<\/h3>\n\n\n\n<p>In den letzten Abschnitten wurden zahlreiche Klassen zum Lesen von Dateien aus dem <code>java.io<\/code>-Paket vorgestellt. Die folgende Grafik zeigt dir noch einmal den Zusammenhang all dieser Klassen. Falls dieses Thema neu f\u00fcr dich ist, hilft es hier immer wieder einmal draufzuschauen. <\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img decoding=\"async\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/12\/Java-FileInputStream-FileReader-InputStreamReader-BufferedInputStream-BufferedReader-de-v2.svg\" alt=\"\u00dcbersicht Java-Klassen: FileInputStream, FileReader, InputStreamReader, BufferedInputStream, BufferedReader\" class=\"wp-image-8903\" style=\"width:720px;height:444px\"\/><\/figure>\n<\/div>\n\n\n<p>Die durchgezogenen Linien stellen den Fluss von Bin\u00e4rdaten dar, die gestrichelten Linien zeigen den Fluss von Zeichen-Daten, also Characters oder Strings. Der <code>FileReader<\/code> ist die Kombination aus <code>FileInputStream<\/code> und <code>InputStreamReader<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"betriebssystem-unabhaengigkeit\">Betriebssystem-Unabh\u00e4ngigkeit<\/h2>\n\n\n\n<p>Im letzten Kapitel haben wir sorglos Textdateien eingelesen. Leider ist es nicht immer ganz so einfach: Zeichenkodierungen, Zeilenumbr\u00fcche und Pfad-Trennzeichen machen auch erfahrenen Programmierern immer wieder das Leben schwer. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"zeichenkodierung\">Zeichenkodierung<\/h3>\n\n\n\n<p>Hast Du schon einmal folgendes gesehen?<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img decoding=\"async\" width=\"1349\" height=\"217\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/charset-mismatch-utf8-iso88591-v2.jpg\" alt=\"Der Text &quot;Zw\u00f6lf Boxk\u00e4mpfer jagen Viktor quer \u00fcber den gro\u00dfen Sylter Deich.&quot; mit fehlerhaft dargestellten Umlauten\" class=\"wp-image-8523\" style=\"width:675px;height:109px\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/charset-mismatch-utf8-iso88591-v2.jpg 1349w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/charset-mismatch-utf8-iso88591-v2-224x36.jpg 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/charset-mismatch-utf8-iso88591-v2-336x54.jpg 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/charset-mismatch-utf8-iso88591-v2-504x81.jpg 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/charset-mismatch-utf8-iso88591-v2-672x108.jpg 672w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/charset-mismatch-utf8-iso88591-v2-400x64.jpg 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/charset-mismatch-utf8-iso88591-v2-600x97.jpg 600w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/charset-mismatch-utf8-iso88591-v2-800x129.jpg 800w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/charset-mismatch-utf8-iso88591-v2-944x152.jpg 944w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/charset-mismatch-utf8-iso88591-v2-1200x193.jpg 1200w\" sizes=\"(max-width: 1349px) 100vw, 1349px\" \/><\/figure>\n<\/div>\n\n\n<p>Oder so etwas?<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img decoding=\"async\" width=\"1349\" height=\"217\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/charset-mismatch-iso88591-utf8.jpg\" alt=\"Der Text &quot;Zw\u00f6lf Boxk\u00e4mpfer jagen Viktor quer \u00fcber den gro\u00dfen Sylter Deich.&quot; mit fehlerhaft dargestellten Umlauten\" class=\"wp-image-8526\" style=\"width:675px;height:109px\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/charset-mismatch-iso88591-utf8.jpg 1349w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/charset-mismatch-iso88591-utf8-224x36.jpg 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/charset-mismatch-iso88591-utf8-336x54.jpg 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/charset-mismatch-iso88591-utf8-504x81.jpg 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/charset-mismatch-iso88591-utf8-672x108.jpg 672w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/charset-mismatch-iso88591-utf8-400x64.jpg 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/charset-mismatch-iso88591-utf8-600x97.jpg 600w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/charset-mismatch-iso88591-utf8-800x129.jpg 800w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/charset-mismatch-iso88591-utf8-944x152.jpg 944w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/charset-mismatch-iso88591-utf8-1200x193.jpg 1200w\" sizes=\"(max-width: 1349px) 100vw, 1349px\" \/><\/figure>\n<\/div>\n\n\n<p>Das passiert, wenn beim Lesen und Schreiben einer Datei unterschiedliche Zeichenkodierungen verwendet werden. <\/p>\n\n\n\n<p>Bei der Vorstellung der Klasse <code>InputStreamReader<\/code> habe ich kurz erw\u00e4hnt, dass diese die eingelesenen Bytes (Zahlen) in Zeichen (Buchstaben, Sonderzeichen, etc.) umwandelt. Die sogenannte Zeichenkodierung bestimmt, welches Zeichen durch welche Zahl kodiert wird. <\/p>\n\n\n\n<p class=\"has-very-light-gray-background-color has-background\"><strong>Eine kurze Geschichte der Zeichenkodierungen<\/strong><br><br>Aus historischen Gr\u00fcnden gibt es verschiedene Zeichenkodierungen. 1963 wurde mit <a rel=\"noopener\" href=\"https:\/\/de.wikipedia.org\/wiki\/American_Standard_Code_for_Information_Interchange\" target=\"_blank\">ASCII<\/a> die erste Zeichenkodierung standardisiert. Diese konnte zun\u00e4chst nur 128 (Steuer-)Zeichen darstellen. Deutsche Umlaute waren genauso wenig enthalten wie z. B. kyrillische oder griechische Buchstaben. Daher wurden zun\u00e4chst mit <a rel=\"noopener\" href=\"https:\/\/de.wikipedia.org\/wiki\/ISO_8859\" target=\"_blank\">ISO-8859<\/a> 15 zus\u00e4tzliche, jeweils 256 Zeichen enthaltende, Zeichenkodierungen f\u00fcr verschiedene Zwecke geschaffen, z. B. <a rel=\"noopener\" href=\"https:\/\/de.wikipedia.org\/wiki\/ISO_8859-1\" target=\"_blank\">ISO-8859-1<\/a> f\u00fcr westeurop\u00e4ische Sprachen, <a rel=\"noopener\" href=\"https:\/\/de.wikipedia.org\/wiki\/ISO_8859-5\" target=\"_blank\">ISO-8859-5<\/a> f\u00fcr Kyrillisch oder <a rel=\"noopener\" href=\"https:\/\/de.wikipedia.org\/wiki\/ISO_8859-7\" target=\"_blank\">ISO-8859-7<\/a> f\u00fcr Griechisch. Microsoft hat f\u00fcr Windows ISO-8859-1 leicht abgewandelt und <a rel=\"noopener\" href=\"https:\/\/de.wikipedia.org\/wiki\/Windows-1252\" target=\"_blank\">Windows-1252<\/a> erschaffen. <br><br>Um dieses Chaos zu beseitigen, wurde 1991 mit ein weltweit einheitlicher Standard geschaffen: <a rel=\"noopener\" href=\"https:\/\/home.unicode.org\/\" target=\"_blank\">Unicode<\/a>. Aktuell (November 2019) enth\u00e4lt Unicode 137.994 verschiedene Zeichen. Durch ein einzelnes Byte k\u00f6nnen maximal 256 Zeichen repr\u00e4sentiert werden. Daher wurden verschiedene Kodierungen entwickelt, um alle Unicode-Zeichen auf ein oder mehrere Bytes abzubilden. Die am meisten verbreitete ist <a rel=\"noopener\" href=\"https:\/\/de.wikipedia.org\/wiki\/UTF-8\" target=\"_blank\">UTF-8<\/a>. Aktuell wird sie auf 94,3 % aller Webseiten verwendet (laut der zuvor verlinkten Wikipedia-Seite).<br><br>Bei UTF-8 werden die ersten 128 Zeichen (also z. B. 'A' bis 'Z', 'a' bis 'z' und '0' bis '9') durch die gleichen Bytes dargestellt, wie in ASCII. Das ist der Grund, warum diese Zeichen \u2013 auch bei falsch eingestellter Kodierung \u2013 immer lesbar sind. Deutsche Umlaute werden durch jeweils zwei Bytes repr\u00e4sentiert. Deshalb stehen im ersten Beispiel oben (in dem ich den Text als UTF-8 gespeichert und dann als ISO-8559-1 geladen habe) an den Stellen der Umlaute jeweils zwei Sonderzeichen. Im zweiten Beispiel habe ich den Text als ISO-8859-1 gespeichert und dann als UTF-8 geladen. Da die Ein-Byte-Repr\u00e4sentation der Umlaute aus ISO-8859-1 in UTF-8 keinen Sinn ergibt, hat der InputStreamReader an den entsprechenden Stellen Fragezeichen eingef\u00fcgt.<\/p>\n\n\n\n<p>Es muss also sichergestellt werden, dass beim Einlesen einer Datei der gleiche Zeichensatz verwendet wird wie beim Speichern. <\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Welche Zeichenkodierung verwendet Java standardm\u00e4\u00dfig zum Lesen von Textdateien?<\/h4>\n\n\n\n<p>Gibt man (wie in den vorangegangenen Beispielen) keine Zeichenkodierung an, wird eine Standard-Kodierung verwendet. Und jetzt wird es gef\u00e4hrlich: Diese kann unterschiedlich sein, je nachdem welche Java-Version und welche Methode man zum Lesen der Datei verwendet:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Verwendet man <code>FileReader<\/code> oder <code>InputStreamReader<\/code>, wird intern die Methode <code>StreamDecoder.forInputStreamReader()<\/code> aufgerufen, welche bei nicht angegebener Zeichenkodierung <code>Charset.defaultCharset()<\/code> verwendet. Diese Methode wiederum liest die Kodierung aus der System-Property \"file.encoding\". Ist diese nicht angegeben, wird bis Java 5 ISO-8859-1 verwendet und ab Java 6 UTF-8.<\/li>\n\n\n\n<li>Verwendet man hingegen <code>Files.readString()<\/code>, <code>Files.readAllLines()<\/code>, <code>Files.lines()<\/code> oder <code>Files.newBufferedReader()<\/code> ohne Zeichenkodierung, wird direkt UTF-8 verwendet, ohne die o. g. System-Property zu pr\u00fcfen.<\/li>\n<\/ul>\n\n\n\n<p>Um auf Nummer Sicher zu gehen, sollte man also immer eine Zeichenkodierung angeben. Wenn m\u00f6glich (d. h. wenn keine Kompatibilit\u00e4t zu alten Dateien sichergestellt werden muss) sollte man die am weitesten verbreitete Kodierung, UTF-8, verwenden.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Wie gebe ich die Zeichenkodierung beim Lesen einer Textdatei an?<\/h4>\n\n\n\n<p>Alle bisher vorgestellten Methoden bieten eine Variante an, bei der die Zeichenkodierung mit \u00fcbergeben werden kann. Die Kodierung wird als Objekt der Klasse <code>Charset<\/code> \u00fcbergeben. Konstanten f\u00fcr Standard-Kodierungen findet man in der Klasse <code>StandardCharsets<\/code>. Im Folgenden findest Du alle Methoden mit der expliziten Angabe von UTF-8 als Kodierung:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>Files.<em>readString<\/em>(path, StandardCharsets.<strong><em>UTF_8<\/em><\/strong>)<\/code><\/li>\n\n\n\n<li><code>Files.<em>readAllLines<\/em>(path, StandardCharsets.<strong><em>UTF_8<\/em><\/strong>)<\/code><\/li>\n\n\n\n<li><code>Files.<em>lines<\/em>(path, StandardCharsets.<strong><em>UTF_8<\/em><\/strong>)<\/code><\/li>\n\n\n\n<li><code><strong>new <\/strong>FileReader(file, StandardCharsets.<strong><em>UTF_8<\/em><\/strong>)<\/code> \/\/ diese Methode gibt es erst seit Java 11<\/li>\n\n\n\n<li><code><strong>new <\/strong>InputStreamReader(is, StandardCharsets.<strong><em>UTF_8<\/em><\/strong>)<\/code><\/li>\n\n\n\n<li><code>Files.<em>newBufferedReader<\/em>(path, StandardCharsets.<strong><em>UTF_8<\/em><\/strong>)<\/code><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"zeilenumbrueche\">Zeilenumbr\u00fcche<\/h3>\n\n\n\n<p>Eine weitere H\u00fcrde beim Laden von Textdateien ist die Tatsache, dass unter Windows Zeilenumbr\u00fcche anders kodiert werden als unter Linux und Mac. <\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Unter Linux und Mac wird ein Zeilenumbruch durch das \"Line Feed\"-Zeichen (Escape-Sequenz \"\\n\", ASCII-Code 10, hexadezimal <code>0A<\/code>) dargestellt.<\/li>\n\n\n\n<li>Windows benutzt die Kombination \"Carriage Return\"+\"Line Feed\" (Escape-Sequenz \"\\r\\n\", ASCII-Codes 13 und 10, bzw. hexadezimal <code>0D0A<\/code>).<\/li>\n<\/ul>\n\n\n\n<p>Gl\u00fccklicherweise k\u00f6nnen heutzutage die meisten Programme mit beiden Kodierungen umgehen. Das war nicht immer so. Fr\u00fcher passierte es beim Austausch von Textdateien zwischen verschiedenen Betriebssystemen regelm\u00e4\u00dfig, dass entweder alle Zeilenumbr\u00fcche verschwanden und der komplette Text in einer Zeile stand, oder aber dass am Ende jeder Zeile ein Sonderzeichen erschien.<\/p>\n\n\n\n<p>Wenn du mit <code>Files.readAllLines()<\/code> oder <code>Files.lines()<\/code> eine Textdatei zeilenweise einliest, erkennt Java die Zeilenumbr\u00fcche automatisch richtig. M\u00f6chtest du einen Text mit eigenem Programmcode in Zeilen aufsplitten, kannst du das wie folgt mit <code>String.split()<\/code> machen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">String&#091;] lines = text.split(<span class=\"hljs-string\">\"r?n\"<\/span>);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Beim Schreiben von Dateien (s. Artikel <a href=\"\/de\/java\/dateien-schnell-einfach-schreiben\/\">\"Dateien schnell und einfach schreiben\"<\/a>) empfehle ich grunds\u00e4tzlich die Linux-Variante zu verwenden, da heutzutage so gut wie jedes Windows-Programm (<a rel=\"noopener\" href=\"https:\/\/devblogs.microsoft.com\/commandline\/extended-eol-in-notepad\/\" target=\"_blank\">seit 2018 sogar Notepad!<\/a>) damit umgehen kann. <\/p>\n\n\n\n<p>Beim Erstellen eines formatierten Strings mit <code>String.format()<\/code> musst Du darauf achten, wie Du den Zeilenumbruch angibst:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>String.<em>format<\/em>(<strong>\"Hallo%n\"<\/strong>)<\/code> f\u00fcgt einen Betriebssystem-spezifischen Zeilenumbruch ein. Das Ergebnis unterscheidet sich also je nach Betriebssystem, auf dem dein Programm ausgef\u00fchrt wird.<\/li>\n\n\n\n<li><code>String.<em>format<\/em>(<strong>\"Hallo\\n\"<\/strong>)<\/code> f\u00fcgt unabh\u00e4ngig vom Betriebssystem immer einen Linux-Zeilenumbruch ein. <\/li>\n<\/ul>\n\n\n\n<p>Du kannst das mit folgendem Programm ausprobieren:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">LineBreaks<\/span> <\/span>{\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">main<\/span><span class=\"hljs-params\">(String&#091;] args)<\/span> <\/span>{\n    System.out.println(String.format(<span class=\"hljs-string\">\"Hallo%n\"<\/span>).length());\n    System.out.println(String.format(<span class=\"hljs-string\">\"Hallon\"<\/span>).length());\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Unter Linux \/ Mac gibt es 6 und 6 aus. Unter Windows hingegen 7 und 6, da der mit \"%n\" f\u00fcr Windows generierte Zeilenumbruch aus einem Zeichen mehr besteht.<\/p>\n\n\n\n<p>Falls du den Zeilentrenner des aktuellen Systems ben\u00f6tigst, erh\u00e4lst du diesen \u00fcber <code>System.<i>lineSeparator<\/i>()<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"pfadnamen\">Pfadnamen<\/h3>\n\n\n\n<p>Auch bei Pfadnamen m\u00fcssen wir Unterschiede zwischen den Betriebssystemen ber\u00fccksichtigen. W\u00e4hrend unter Windows absolute Pfade mit einem Laufwerksbuchstaben und einem Doppelpunkt (z. B. \"C:\") beginnen und Verzeichnisse durch einen Backslash ('\\') getrennt werden, werden diese unter Linux durch einen regul\u00e4ren Schr\u00e4gstrich ('\/') getrennt, welcher auch am Anfang von absoluten Pfaden steht. <\/p>\n\n\n\n<p>Beispielsweise lautet der Pfad meiner Maven-Konfigurationsdatei:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>... unter Windows: <code>C:\\Users\\sven\\.m2\\settings.xml<\/code><\/li>\n\n\n\n<li>... unter Linux: <code>\/home\/sven\/.m2\/settings.xml<\/code> <\/li>\n<\/ul>\n\n\n\n<p>Das im aktuellen Betriebssystem verwendete Trennzeichen bekommst Du \u00fcber die Konstante <code>File.<strong><i>separator<\/i><\/strong><\/code> oder die Methode <code>FileSystems.<i>getDefault<\/i>().getSeparator()<\/code>. <\/p>\n\n\n\n<p>Im Normalfall solltest Du das Trennzeichen nicht direkt ben\u00f6tigen. Java stellt Dir die Klassen <code>java.io.File<\/code> und, ab Java 7, <code>java.nio.file.Path<\/code> zur Verf\u00fcgung, um Verzeichnis- und Dateipfade zu konstruieren, ohne das Trennzeichen angeben zu m\u00fcssen.<\/p>\n\n\n\n<p>An dieser Stelle gehe ich nicht weiter ins Detail. Datei- und Verzeichnisnamen, relative und absolute Pfadangaben, alte API und NIO.2 machen die Thematik recht komplex. Ich werde das Thema daher in einem separaten Artikel behandeln.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"zusammenfassung-und-ausblick\">Zusammenfassung und Ausblick<\/h2>\n\n\n\n<p>In diesem Artikel hast du verschiedene Methoden kennengelernt, um in Java Text- und Bin\u00e4rdateien zu lesen. Au\u00dferdem haben wir uns angesehen, was zu beachten ist, wenn deine Software auch auf anderen Betriebssystemen als deinem lauff\u00e4hig sein soll.<\/p>\n\n\n\n<p>Im zweiten Teil wirst du die entsprechenden Methoden zum <a href=\"\/de\/java\/dateien-schnell-einfach-schreiben\/\">Schreiben von Dateien in Java<\/a> kennenlernen.<\/p>\n\n\n\n<p>Im Anschluss daran werden folgende Themen behandelt:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"\/de\/java\/dateinamen-verzeichnisnamen-file-path-paths\/\">Konstruieren von Datei- und Verzeichnispfaden mit den Klassen <code>File<\/code>, <code>Path<\/code> und <code>Paths<\/code><\/a><\/li>\n\n\n\n<li><a href=\"\/de\/java\/verzeichnisse-listen-dateien-verschieben-kopieren-loeschen\/#Verzeichnisoperationen\">Verzeichnis-Operationen, wie z. B. das Einlesen der Dateiliste eines Verzeichnisses<\/a><\/li>\n\n\n\n<li><a href=\"\/de\/java\/verzeichnisse-listen-dateien-verschieben-kopieren-loeschen\/#Wie_verschiebt_man_eine_Datei_in_Java\">Kopieren, Verschieben und L\u00f6schen von Dateien <\/a><\/li>\n\n\n\n<li><a href=\"\/de\/java\/verzeichnisse-listen-dateien-verschieben-kopieren-loeschen\/#Eine_temporaere_Datei_erstellen\">Erstellen von tempor\u00e4ren Dateien<\/a><\/li>\n\n\n\n<li><a href=\"\/de\/java\/strukturierte-daten-schreiben-lesen-dataoutputstream-datainputstream\/\">Laden und Schreiben strukturierter Daten mit <code>DataOutputStream<\/code> und <code>DataInputStream<\/code><\/a><\/li>\n<\/ul>\n\n\n\n<p>Und zum Abschluss der Serie kommen wir zu fortgeschrittenen Themen:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Die in Java 1.4 eingef\u00fchrten <a href=\"https:\/\/www.happycoders.eu\/de\/java\/filechannel-memory-mapped-io-locks\/\">NIO-Channels und Buffer<\/a>, um insbesondere das Arbeiten mit gro\u00dfen Dateien zu beschleunigen<\/li>\n\n\n\n<li><a href=\"https:\/\/www.happycoders.eu\/de\/java\/filechannel-memory-mapped-io-locks\/#Memory-mapped_Files_Wie_man_einen_Teil_einer_Datei_in_den_Speicher_mappt\">Memory-mapped I\/O<\/a> f\u00fcr rasend schnellen Dateizugriff ohne Streams<\/li>\n\n\n\n<li><a href=\"https:\/\/www.happycoders.eu\/de\/java\/filechannel-memory-mapped-io-locks\/#File_Locking_Sperren_von_Dateibereichen\">File Locking<\/a>, um parallel \u2013 also aus mehreren Threads oder Prozessen \u2013 konfliktfrei auf dieselben Dateien zuzugreifen <\/li>\n<\/ul>\n\n\n\n<p>Wenn du informiert werden willst, wenn der zweite Teil ver\u00f6ffentlicht wird, dann <a href=\"#\" data-formkit-toggle=\"d8ee997126\">klicke hier<\/a>, um dich f\u00fcr den HappyCoders-Newsletter anzumelden. Und nat\u00fcrlich w\u00fcrde ich mich auch freuen, wenn du den Artikel \u00fcber einen der Buttons am Ende teilst.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Dieser Artikel stellt Methoden zum Lesen und Schreiben von Dateien in Java vor.<\/p>\n<p>Nachdem du den Artikel gelesen hast, wirst du genau wissen, wann du FileReader, FileInputStream, InputStreamReader, BufferedInputStream und BufferedReader verwenden solltest.<\/p>\n","protected":false},"author":1,"featured_media":34424,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_seopress_robots_primary_cat":"none","_seopress_titles_title":"","_seopress_titles_desc":"Wie liest man Dateien in Java? Schnell und einfach Text- und Bin\u00e4rdateien einlesen. Wann verwendet man FileReader und FileInputStream?","_seopress_robots_index":"","_uag_custom_page_level_css":"","_wp_convertkit_post_meta":{"form":"-1","landing_page":"","tag":"0","restrict_content":"0"},"_metis_text_type":"standard","_metis_text_length":22016,"_post_count":0,"footnotes":""},"categories":[64],"tags":[166],"class_list":["post-8371","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-java","tag-java-dateien"],"uagb_featured_image_src":{"full":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/java-read-file.jpg",1770,986,false],"thumbnail":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/java-read-file.jpg",150,84,false],"medium":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/java-read-file.jpg",300,167,false],"medium_large":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/java-read-file.jpg",768,428,false],"large":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/java-read-file.jpg",1024,570,false],"feature_thumb_224":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/java-read-file-224x125.jpg",224,125,true],"feature_thumb_336":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/java-read-file-336x187.jpg",336,187,true],"feature_thumb_504":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/java-read-file-504x281.jpg",504,281,true],"feature_thumb_672":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/java-read-file-672x374.jpg",672,374,true],"half_400":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/java-read-file-400x223.jpg",400,223,true],"half_600":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/java-read-file-600x334.jpg",600,334,true],"full_800":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/java-read-file-800x446.jpg",800,446,true],"full_944":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/java-read-file-944x526.jpg",944,526,true],"full_1200":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/java-read-file-1200x668.jpg",1200,668,true],"wide_1180":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/java-read-file-1180x490.jpg",1180,490,true],"wide_1770":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/java-read-file-1770x735.jpg",1770,735,true],"1536x1536":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/java-read-file.jpg",1536,856,false],"2048x2048":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/11\/java-read-file.jpg",1770,986,false]},"uagb_author_info":{"display_name":"Sven Woltmann","author_link":"https:\/\/www.happycoders.eu\/de\/author\/sven\/"},"uagb_comment_info":2,"uagb_excerpt":"Dieser Artikel stellt Methoden zum Lesen und Schreiben von Dateien in Java vor. Nachdem du den Artikel gelesen hast, wirst du genau wissen, wann du FileReader, FileInputStream, InputStreamReader, BufferedInputStream und BufferedReader verwenden solltest.","public_identification_id":"48288fa5257d4259acc929a1d190e8cf","private_identification_id":"06ef3fd6344b47c9b546c99c9f9c11a8","_links":{"self":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/8371","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/comments?post=8371"}],"version-history":[{"count":10,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/8371\/revisions"}],"predecessor-version":[{"id":41966,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/8371\/revisions\/41966"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/media\/34424"}],"wp:attachment":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/media?parent=8371"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/categories?post=8371"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/tags?post=8371"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}