From 25031175133dbfa058e298646c7e1d52dabf1fad Mon Sep 17 00:00:00 2001 From: Cay Horstmann Date: Thu, 1 Feb 2024 20:39:04 +0100 Subject: [PATCH 1/6] Modern I/O article (issue #26) --- .../02_modern_io/index.md | 252 ++++++++++++++++++ 1 file changed, 252 insertions(+) create mode 100644 app/pages/learn/01_tutorial/04_mastering-the-api/02_modern_io/index.md diff --git a/app/pages/learn/01_tutorial/04_mastering-the-api/02_modern_io/index.md b/app/pages/learn/01_tutorial/04_mastering-the-api/02_modern_io/index.md new file mode 100644 index 0000000..e45d09d --- /dev/null +++ b/app/pages/learn/01_tutorial/04_mastering-the-api/02_modern_io/index.md @@ -0,0 +1,252 @@ +# Common I/O Tasks in Modern Java + +This article focuses on tasks that application programmers are likely to encounter, particularly in web applications, such as: + +* Reading and writing text files +* Reading text, images, JSON from the web +* Visiting files in a directory +* Reading a zip file +* Creating a temporary file or directory + +The Java API supports many other tasks, which are explained in detail in the [Java I/O API tutorial](https://dev.java/learn/java-io/). + +Modern, at the time of this writing, means features that are out of preview in Java 21. In particular: + +* UTF-8 is the default for I/O since Java 18 ([JEP 400](https://openjdk.org/jeps/400)) +* The `java.nio.file.Files` class, which first appeared in Java 7, added useful methods in Java 8, 11, and 12 +* `java.io.InputStream` gained useful methods in Java 9, 11, and 12 +* The `java.io.File` and `java.io.BufferedReader` classes are now thoroughly obsolete, even though they appear frequently in web searches and AI chats. + +## Reading Text Files + +Tou can read a text file into a string like this: + +``` +String content = Files.readString(path); +``` + +Here, `path` is an instance of `java.nio.Path`, obtained like this: + +``` +var path = Path.of("/usr/share/dict/words"); +``` + +If you want the file as a sequence of lines, call + +``` +List lines = Files.readAllLines(path); +``` + +If the file is large, process the lines lazily as a `Stream`: + +``` +try (Stream lines = Files.lines(path)) +{ + . . . +} +``` + +Also use `Files.lines` if you can naturally process lines with stream operations (such as `map`, `filter`) . + +Note that the stream returned by `Files.lines` needs to be closed. To ensure that this happens, use a `try`-with-resources statement, as in the preceding code snippet. + +There is no longer a good reason to use the `readLine` method of `java.io.BufferedReader`. + +To split your input into something else than lines, use a `java.util.Scanner`. For example, here is how you can read words, separated by non-letters: + +``` +Stream tokens = new Scanner(path).useDelimiter("\\PL+").tokens(); +``` + +## Writing Text Files + +You can write a string to a text file with a single call: + +``` +String content = . . .; +Files.writeString(path, content); +``` + +If you have a list of lines rather than a single string, use: + +``` +List lines = . . .; +Files.write(path, lines); +``` + +For more general output, use a `PrintWriter` so that you can use the `printf` method: + +``` +var writer = new PrintWriter(path.toFile()); +writer.printf("Hello, %s, next year you'll be %d years old!%n", name, age + 1); +``` + +Weirdly enough, as of Java 21, there is no `PrintWriter` constructor with a `Path` parameter. + +The `BufferedWriter` class can only write strings without formatting them. That is ok if you use the `String.formatted` method: + +``` +var writer = Files.newBufferedWriter(path); +writer.write("Hello, %s, next year you'll be %d years old!%n".formatted(name, age + 1)); +``` + +Or, with the `FMT` template (which is still in preview): + +``` +writer.write(FMT."Hello, %s\{name}, next year you'll be %d\{age + 1} years old!%n"); +``` + +Remember to close the `writer` when you are done. + +## Reading From an Input Stream + +Perhaps the most common reason to use a stream is to read something from a web site. + +If you need to set request headers or read response headers, use the `HttpClient`: + +``` +HttpClient client = HttpClient.newBuilder().build(); +HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("https://horstmann.com/index.html")) + .GET() + .build(); +HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); +String result = response.body(); +``` + +That is overkill if all you want is the data. Instead, use: + +``` +InputStream in = new URI("https://horstmann.com/index.html").toURL().openStream(); +``` + +Then read the data into a byte array and optionally turn them into a string: + +``` +byte[] bytes = in.readAllBytes(); +String result = new String(bytes); +``` + +Or transfer the data to an output stream: + +``` +OutputStream out = Files.newOutputStream(path); +in.transferTo(out); +``` + +Nowadays, there is no need to read or write bytes, or chunks of bytes, in a loop. + +But do you really need an input stream? Many APIs give you the option to read from a file or URL. + +Your favorite JSON library is likely to have methods for reading from a file or URL. For example, with [Jackson jr](https://github.com/FasterXML/jackson-jr): + +``` +URL url = new URI("https://dog.ceo/api/breeds/image/random").toURL(); +Map result = JSON.std.mapFrom(url); +``` + +Here is how to read the dog image from the preceding call: + +``` +url = new URI(result.get("message").toString()).toURL(); +BufferedImage img = javax.imageio.ImageIO.read(url) +``` + +This is better than passing an input stream to the `read` method, because the library can use additional information from the URL to determine the image type. + +## The Files API + +The `java.nio.file.Files` class provides a comprehensive set of file operations, such as creating, copying, moving, and deleting fies and directories. The [File System Basics](https://dev.java/learn/java-io/file-system/) tutorial provides a thorough description. In this section, I highlight a few common tasks. + +### Traversing Entries in Directories and Subdirectories + +For most situations you can use one of two methods. The `Files.list` method visits all entries (files, subdirectories, symbolic links) of a directory. + +``` +try (Stream entries = Files.list(pathToDirectory)) +{ + . . . +} +``` + +Use a `try`-with-resources statement to ensure that the stream object, which keeps track of the iteration, will be closed. + +If you also want to visit the entries of descendant directories, instead use the method + +``` +Stream entries = Files.walk(pathToDirectory); +``` + +Then simply use stream methods to home in on the entries that you are interested in, and to collect the results: + +``` +try (Stream entries = Files.walk(pathToDirectory)) { + List htmlFiles = entries.filter(p -> p.toString().endsWith("html")).toList(); + . . . +} +``` + +Here are the other methods for traversing directory entries: + +* An overloaded version of `Files.walk` lets you limit the depth of the traversed tree. +* Two `Files.walkFileTree` methods provide more control over the iteration process, by notifying a `FileVisitor` when a directory is visited for the first and last time. This can be occasionally useful, in particularly for emptying and deleting a tree of directories. See the tutorial [=https://dev.java/learn/java-io/file-system/walking-tree/ Walking the File Tree](null) for details. Unless you need this control, use the simpler `Files.walk` method. +* The `Files.find` method is just like `Files.walk`, but you provide a filter that inspects each path and its `BasicFileAttributes`. This is slightly more efficient than reading the attributes separately for each file. +* Two `Files.newDirectoryStream` methods yields `DirectoryStream` instances, which can be used in enhanced `for` loops. There is no advantage over using `Files.list`. +* The legacy `File.list` or `File.listFiles` methods return file names or `File` objects. These are now obsolete. + +### Working with Zip Files + +Ever since Java 1.1, the `ZipInputStream` and `ZipOutputStream` classes provide an API for processing zip files. But the API is a bit clunky. Java 8 introduced a much nicer *zip file system*: + +``` +FileSystem fs = FileSystems.newFileSystem(pathToZipFile); +``` + +You can then use the methods of the `Files` class. Here we get a list of all files in the zip file: + +``` +try (Stream entries = Files.walk(fs.getPath("/"))) { + List filesInZip = entries.filter(Files::isRegularFile).toList(); +} +``` + +To read the file contents, just use `Files.readString` or `Files.readAllBytes`: + +``` +String contents = Files.readString(fs.getPath("/LICENSE")); +``` + +You can remove files with `Files.delete`. To add or replace files, simply use `Files.writeString` or `Files.write`. + +You must close the file system so that the changes are written to the zip file. Call + +``` +fs.close(); +``` + +or use a `try`-with-resources statement. + +### Creating Temporary Files and Directories + +Fairly often, I need to collect user input, produce files, and run an external process. Then I use temporary files, which are gone after the next reboot, or a temporary directory that I erase after the process has completed. + +The calls + +``` +Path filePath = Files.createTempFile("myapp", ".txt"); +Path dirPath = Files.createTempDirectory("myapp"); +``` + +create a temporary file or directory in a suitable location (`/tmp` in Linux) with the given prefix and, for a file, suffix. + +## Conclusion + +Web searches and AI chats can suggest needlessly complex code for common I/O operations. There are often better alternatives: + +1. You don't need a loop to read or write strings or byte arrays. +2. You may not even need a stream, reader or writer. +3. Become familiar with the `Files` methods for creating, copying, moving, and deleting files and directories. +4. Use `Files.list` or `Files.walk` to traverse directory entries. +5. Use a zip file system for processing zip files. +6. Stay away from the legacy `File` class. + From fb1a8388b39bcd756a2b1e7be78b9b20a306a836 Mon Sep 17 00:00:00 2001 From: Cay Horstmann Date: Sat, 3 Feb 2024 09:37:36 +0100 Subject: [PATCH 2/6] Incorporated comments from danthe1st --- .../02_modern_io/index.md | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/app/pages/learn/01_tutorial/04_mastering-the-api/02_modern_io/index.md b/app/pages/learn/01_tutorial/04_mastering-the-api/02_modern_io/index.md index e45d09d..42df9e3 100644 --- a/app/pages/learn/01_tutorial/04_mastering-the-api/02_modern_io/index.md +++ b/app/pages/learn/01_tutorial/04_mastering-the-api/02_modern_io/index.md @@ -46,7 +46,7 @@ try (Stream lines = Files.lines(path)) } ``` -Also use `Files.lines` if you can naturally process lines with stream operations (such as `map`, `filter`) . +Also use `Files.lines` if you can naturally process lines with stream operations (such as `map`, `filter`). Note that the stream returned by `Files.lines` needs to be closed. To ensure that this happens, use a `try`-with-resources statement, as in the preceding code snippet. @@ -58,6 +58,10 @@ To split your input into something else than lines, use a `java.util.Scanner`. F Stream tokens = new Scanner(path).useDelimiter("\\PL+").tokens(); ``` +The `Scanner` class also has methods for reading numbers, but it is generally simpler to read the input as one string per line, or a single string, and then parse it. + +Be careful when parsing numbers from text files, since their format may be locale-dependent. For example, the input `100.000` is 100.0 in the US locale but 100000.0 in the German locale. Use `java.text.NumberFormat` for locale-specific parsing. Alternatively, you may be able to use `Integer.parseInt`/`Double.parseDouble`. + ## Writing Text Files You can write a string to a text file with a single call: @@ -74,26 +78,23 @@ List lines = . . .; Files.write(path, lines); ``` -For more general output, use a `PrintWriter` so that you can use the `printf` method: +For more general output, use a `PrintWriter` if you want to use the `printf` method: ``` var writer = new PrintWriter(path.toFile()); -writer.printf("Hello, %s, next year you'll be %d years old!%n", name, age + 1); +writer.printf(locale, "Hello, %s, next year you'll be %d years old!%n", name, age + 1); ``` +Note that `printf` is locale-specific. When writing numbers, be sure to write them in the appropriate format. Instead of using `printf`, consider `java.text.NumberFormat` or `Integer.toString`/`Double.toString`. + Weirdly enough, as of Java 21, there is no `PrintWriter` constructor with a `Path` parameter. -The `BufferedWriter` class can only write strings without formatting them. That is ok if you use the `String.formatted` method: +If you don't use `printf`, you can use the `BufferedWriter` class and write strings with the `write` method. ``` var writer = Files.newBufferedWriter(path); -writer.write("Hello, %s, next year you'll be %d years old!%n".formatted(name, age + 1)); -``` - -Or, with the `FMT` template (which is still in preview): - -``` -writer.write(FMT."Hello, %s\{name}, next year you'll be %d\{age + 1} years old!%n"); +writer.write(line); // Does not write a line separator +writer.newLine(); ``` Remember to close the `writer` when you are done. @@ -134,7 +135,7 @@ OutputStream out = Files.newOutputStream(path); in.transferTo(out); ``` -Nowadays, there is no need to read or write bytes, or chunks of bytes, in a loop. +Note that no loop is required if you simply want to read all bytes of an input stream. But do you really need an input stream? Many APIs give you the option to read from a file or URL. @@ -189,7 +190,7 @@ try (Stream entries = Files.walk(pathToDirectory)) { Here are the other methods for traversing directory entries: * An overloaded version of `Files.walk` lets you limit the depth of the traversed tree. -* Two `Files.walkFileTree` methods provide more control over the iteration process, by notifying a `FileVisitor` when a directory is visited for the first and last time. This can be occasionally useful, in particularly for emptying and deleting a tree of directories. See the tutorial [=https://dev.java/learn/java-io/file-system/walking-tree/ Walking the File Tree](null) for details. Unless you need this control, use the simpler `Files.walk` method. +* Two `Files.walkFileTree` methods provide more control over the iteration process, by notifying a `FileVisitor` when a directory is visited for the first and last time. This can be occasionally useful, in particularly for emptying and deleting a tree of directories. See the tutorial [Walking the File Tree](https://dev.java/learn/java-io/file-system/walking-tree) for details. Unless you need this control, use the simpler `Files.walk` method. * The `Files.find` method is just like `Files.walk`, but you provide a filter that inspects each path and its `BasicFileAttributes`. This is slightly more efficient than reading the attributes separately for each file. * Two `Files.newDirectoryStream` methods yields `DirectoryStream` instances, which can be used in enhanced `for` loops. There is no advantage over using `Files.list`. * The legacy `File.list` or `File.listFiles` methods return file names or `File` objects. These are now obsolete. From 3658510300c84dcff825298b554d6ddbddf46929 Mon Sep 17 00:00:00 2001 From: Cay Horstmann Date: Wed, 6 Mar 2024 11:00:27 +0100 Subject: [PATCH 3/6] Incorporated more comments from danthe1st --- .../04_mastering-the-api/02_modern_io/index.md | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/app/pages/learn/01_tutorial/04_mastering-the-api/02_modern_io/index.md b/app/pages/learn/01_tutorial/04_mastering-the-api/02_modern_io/index.md index 42df9e3..338cc72 100644 --- a/app/pages/learn/01_tutorial/04_mastering-the-api/02_modern_io/index.md +++ b/app/pages/learn/01_tutorial/04_mastering-the-api/02_modern_io/index.md @@ -10,7 +10,7 @@ This article focuses on tasks that application programmers are likely to encount The Java API supports many other tasks, which are explained in detail in the [Java I/O API tutorial](https://dev.java/learn/java-io/). -Modern, at the time of this writing, means features that are out of preview in Java 21. In particular: +This article focuses on API improvements since Java 8. In particular: * UTF-8 is the default for I/O since Java 18 ([JEP 400](https://openjdk.org/jeps/400)) * The `java.nio.file.Files` class, which first appeared in Java 7, added useful methods in Java 8, 11, and 12 @@ -31,6 +31,8 @@ Here, `path` is an instance of `java.nio.Path`, obtained like this: var path = Path.of("/usr/share/dict/words"); ``` +Before Java 18, you were strongly encouraged to specify the character encoding with any file operations that read or write strings. Nowadays, by far the most common character encoding is UTF-8, but for backwards compatibility, Java used the "platform encoding", which can be a legacy encoding on Windows. To ensure portability, text I/O operations needed parameters `StandardCharsets.UTF_8`. This is no longer necessary. + If you want the file as a sequence of lines, call ``` @@ -200,9 +202,13 @@ Here are the other methods for traversing directory entries: Ever since Java 1.1, the `ZipInputStream` and `ZipOutputStream` classes provide an API for processing zip files. But the API is a bit clunky. Java 8 introduced a much nicer *zip file system*: ``` -FileSystem fs = FileSystems.newFileSystem(pathToZipFile); +try (FileSystem fs = FileSystems.newFileSystem(pathToZipFile)) { + . . . +} ``` +The `try`-with-resources statement ensures that the `close` method is called after the zip file operations. That method updates the zip file to reflect any changes in the file system. + You can then use the methods of the `Files` class. Here we get a list of all files in the zip file: ``` @@ -219,14 +225,6 @@ String contents = Files.readString(fs.getPath("/LICENSE")); You can remove files with `Files.delete`. To add or replace files, simply use `Files.writeString` or `Files.write`. -You must close the file system so that the changes are written to the zip file. Call - -``` -fs.close(); -``` - -or use a `try`-with-resources statement. - ### Creating Temporary Files and Directories Fairly often, I need to collect user input, produce files, and run an external process. Then I use temporary files, which are gone after the next reboot, or a temporary directory that I erase after the process has completed. From 3fd85468e5d43628ec810ae983dacef817c8ab3e Mon Sep 17 00:00:00 2001 From: Cay Horstmann Date: Sat, 9 Mar 2024 18:43:29 +0100 Subject: [PATCH 4/6] nipafx comments --- .../02_modern_io/index.md | 84 +++++++++---------- 1 file changed, 40 insertions(+), 44 deletions(-) diff --git a/app/pages/learn/01_tutorial/04_mastering-the-api/02_modern_io/index.md b/app/pages/learn/01_tutorial/04_mastering-the-api/02_modern_io/index.md index 338cc72..84e7a21 100644 --- a/app/pages/learn/01_tutorial/04_mastering-the-api/02_modern_io/index.md +++ b/app/pages/learn/01_tutorial/04_mastering-the-api/02_modern_io/index.md @@ -5,7 +5,7 @@ This article focuses on tasks that application programmers are likely to encount * Reading and writing text files * Reading text, images, JSON from the web * Visiting files in a directory -* Reading a zip file +* Reading a ZIP file * Creating a temporary file or directory The Java API supports many other tasks, which are explained in detail in the [Java I/O API tutorial](https://dev.java/learn/java-io/). @@ -21,13 +21,13 @@ This article focuses on API improvements since Java 8. In particular: Tou can read a text file into a string like this: -``` +```java String content = Files.readString(path); ``` Here, `path` is an instance of `java.nio.Path`, obtained like this: -``` +```java var path = Path.of("/usr/share/dict/words"); ``` @@ -35,28 +35,25 @@ Before Java 18, you were strongly encouraged to specify the character encoding w If you want the file as a sequence of lines, call -``` +```java List lines = Files.readAllLines(path); ``` If the file is large, process the lines lazily as a `Stream`: -``` -try (Stream lines = Files.lines(path)) -{ - . . . +```java +try (Stream lines = Files.lines(path)) { + . . . } ``` -Also use `Files.lines` if you can naturally process lines with stream operations (such as `map`, `filter`). - -Note that the stream returned by `Files.lines` needs to be closed. To ensure that this happens, use a `try`-with-resources statement, as in the preceding code snippet. +Also use `Files.lines` if you can naturally process lines with stream operations (such as `map`, `filter`). Note that the stream returned by `Files.lines` needs to be closed. To ensure that this happens, use a `try`-with-resources statement, as in the preceding code snippet. There is no longer a good reason to use the `readLine` method of `java.io.BufferedReader`. To split your input into something else than lines, use a `java.util.Scanner`. For example, here is how you can read words, separated by non-letters: -``` +```java Stream tokens = new Scanner(path).useDelimiter("\\PL+").tokens(); ``` @@ -68,21 +65,21 @@ Be careful when parsing numbers from text files, since their format may be local You can write a string to a text file with a single call: -``` +```java String content = . . .; Files.writeString(path, content); ``` If you have a list of lines rather than a single string, use: -``` +```java List lines = . . .; Files.write(path, lines); ``` For more general output, use a `PrintWriter` if you want to use the `printf` method: -``` +```java var writer = new PrintWriter(path.toFile()); writer.printf(locale, "Hello, %s, next year you'll be %d years old!%n", name, age + 1); ``` @@ -93,7 +90,7 @@ Weirdly enough, as of Java 21, there is no `PrintWriter` constructor with a `Pat If you don't use `printf`, you can use the `BufferedWriter` class and write strings with the `write` method. -``` +```java var writer = Files.newBufferedWriter(path); writer.write(line); // Does not write a line separator writer.newLine(); @@ -107,32 +104,32 @@ Perhaps the most common reason to use a stream is to read something from a web s If you need to set request headers or read response headers, use the `HttpClient`: -``` +```java HttpClient client = HttpClient.newBuilder().build(); HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create("https://horstmann.com/index.html")) - .GET() - .build(); + .uri(URI.create("https://horstmann.com/index.html")) + .GET() + .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); String result = response.body(); ``` That is overkill if all you want is the data. Instead, use: -``` +```java InputStream in = new URI("https://horstmann.com/index.html").toURL().openStream(); ``` Then read the data into a byte array and optionally turn them into a string: -``` +```java byte[] bytes = in.readAllBytes(); String result = new String(bytes); ``` Or transfer the data to an output stream: -``` +```java OutputStream out = Files.newOutputStream(path); in.transferTo(out); ``` @@ -143,14 +140,14 @@ But do you really need an input stream? Many APIs give you the option to read fr Your favorite JSON library is likely to have methods for reading from a file or URL. For example, with [Jackson jr](https://github.com/FasterXML/jackson-jr): -``` +```java URL url = new URI("https://dog.ceo/api/breeds/image/random").toURL(); Map result = JSON.std.mapFrom(url); ``` Here is how to read the dog image from the preceding call: -``` +```java url = new URI(result.get("message").toString()).toURL(); BufferedImage img = javax.imageio.ImageIO.read(url) ``` @@ -165,10 +162,9 @@ The `java.nio.file.Files` class provides a comprehensive set of file operations, For most situations you can use one of two methods. The `Files.list` method visits all entries (files, subdirectories, symbolic links) of a directory. -``` -try (Stream entries = Files.list(pathToDirectory)) -{ - . . . +```java +try (Stream entries = Files.list(pathToDirectory)) { + . . . } ``` @@ -176,16 +172,16 @@ Use a `try`-with-resources statement to ensure that the stream object, which kee If you also want to visit the entries of descendant directories, instead use the method -``` +```java Stream entries = Files.walk(pathToDirectory); ``` Then simply use stream methods to home in on the entries that you are interested in, and to collect the results: -``` +```java try (Stream entries = Files.walk(pathToDirectory)) { - List htmlFiles = entries.filter(p -> p.toString().endsWith("html")).toList(); - . . . + List htmlFiles = entries.filter(p -> p.toString().endsWith("html")).toList(); + . . . } ``` @@ -197,29 +193,29 @@ Here are the other methods for traversing directory entries: * Two `Files.newDirectoryStream` methods yields `DirectoryStream` instances, which can be used in enhanced `for` loops. There is no advantage over using `Files.list`. * The legacy `File.list` or `File.listFiles` methods return file names or `File` objects. These are now obsolete. -### Working with Zip Files +### Working with ZIP Files -Ever since Java 1.1, the `ZipInputStream` and `ZipOutputStream` classes provide an API for processing zip files. But the API is a bit clunky. Java 8 introduced a much nicer *zip file system*: +Ever since Java 1.1, the `ZipInputStream` and `ZipOutputStream` classes provide an API for processing ZIP files. But the API is a bit clunky. Java 8 introduced a much nicer *ZIP file system*: -``` +```java try (FileSystem fs = FileSystems.newFileSystem(pathToZipFile)) { - . . . + . . . } ``` -The `try`-with-resources statement ensures that the `close` method is called after the zip file operations. That method updates the zip file to reflect any changes in the file system. +The `try`-with-resources statement ensures that the `close` method is called after the ZIP file operations. That method updates the ZIP file to reflect any changes in the file system. -You can then use the methods of the `Files` class. Here we get a list of all files in the zip file: +You can then use the methods of the `Files` class. Here we get a list of all files in the ZIP file: -``` +```java try (Stream entries = Files.walk(fs.getPath("/"))) { - List filesInZip = entries.filter(Files::isRegularFile).toList(); + List filesInZip = entries.filter(Files::isRegularFile).toList(); } ``` To read the file contents, just use `Files.readString` or `Files.readAllBytes`: -``` +```java String contents = Files.readString(fs.getPath("/LICENSE")); ``` @@ -231,7 +227,7 @@ Fairly often, I need to collect user input, produce files, and run an external p The calls -``` +```java Path filePath = Files.createTempFile("myapp", ".txt"); Path dirPath = Files.createTempDirectory("myapp"); ``` @@ -246,6 +242,6 @@ Web searches and AI chats can suggest needlessly complex code for common I/O ope 2. You may not even need a stream, reader or writer. 3. Become familiar with the `Files` methods for creating, copying, moving, and deleting files and directories. 4. Use `Files.list` or `Files.walk` to traverse directory entries. -5. Use a zip file system for processing zip files. +5. Use a ZIP file system for processing ZIP files. 6. Stay away from the legacy `File` class. From b6d81ba19ee83225f77e10853dc21f705069aa13 Mon Sep 17 00:00:00 2001 From: Chad Arimura Date: Wed, 24 Apr 2024 16:11:21 -0700 Subject: [PATCH 5/6] keep in mastering the api section --- .../02_modern_io/{index.md => 01_modern_io.md} | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) rename app/pages/learn/01_tutorial/04_mastering-the-api/02_modern_io/{index.md => 01_modern_io.md} (95%) diff --git a/app/pages/learn/01_tutorial/04_mastering-the-api/02_modern_io/index.md b/app/pages/learn/01_tutorial/04_mastering-the-api/02_modern_io/01_modern_io.md similarity index 95% rename from app/pages/learn/01_tutorial/04_mastering-the-api/02_modern_io/index.md rename to app/pages/learn/01_tutorial/04_mastering-the-api/02_modern_io/01_modern_io.md index 84e7a21..946e56a 100644 --- a/app/pages/learn/01_tutorial/04_mastering-the-api/02_modern_io/index.md +++ b/app/pages/learn/01_tutorial/04_mastering-the-api/02_modern_io/01_modern_io.md @@ -1,4 +1,20 @@ -# Common I/O Tasks in Modern Java +--- +id: api.modernio +title: "Common I/O Tasks in Modern Java" +type: tutorial +category: api +category_order: 2 +layout: learn/tutorial.html +subheader_select: tutorials +main_css_id: learn +last_update: 2024-04-24 +description: "This article focuses on tasks that application programmers are likely to encounter, particularly in web applications, such as reading and writing text files, reading text, images, JSON from the web, and more." +author: ["CayHorstmann"] +--- + +  + +## Introduction This article focuses on tasks that application programmers are likely to encounter, particularly in web applications, such as: From f2677b125a08fa708a74a5307f1c963b13b6fe77 Mon Sep 17 00:00:00 2001 From: Chad Arimura Date: Thu, 25 Apr 2024 07:17:52 -0700 Subject: [PATCH 6/6] fixed typos --- .../04_mastering-the-api/02_modern_io/01_modern_io.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/pages/learn/01_tutorial/04_mastering-the-api/02_modern_io/01_modern_io.md b/app/pages/learn/01_tutorial/04_mastering-the-api/02_modern_io/01_modern_io.md index 946e56a..54e86ee 100644 --- a/app/pages/learn/01_tutorial/04_mastering-the-api/02_modern_io/01_modern_io.md +++ b/app/pages/learn/01_tutorial/04_mastering-the-api/02_modern_io/01_modern_io.md @@ -35,7 +35,7 @@ This article focuses on API improvements since Java 8. In particular: ## Reading Text Files -Tou can read a text file into a string like this: +You can read a text file into a string like this: ```java String content = Files.readString(path); @@ -172,7 +172,7 @@ This is better than passing an input stream to the `read` method, because the li ## The Files API -The `java.nio.file.Files` class provides a comprehensive set of file operations, such as creating, copying, moving, and deleting fies and directories. The [File System Basics](https://dev.java/learn/java-io/file-system/) tutorial provides a thorough description. In this section, I highlight a few common tasks. +The `java.nio.file.Files` class provides a comprehensive set of file operations, such as creating, copying, moving, and deleting files and directories. The [File System Basics](https://dev.java/learn/java-io/file-system/) tutorial provides a thorough description. In this section, I highlight a few common tasks. ### Traversing Entries in Directories and Subdirectories