Skip to content

Commit 3fd8546

Browse files
committed
nipafx comments
1 parent 3658510 commit 3fd8546

File tree

1 file changed

+40
-44
lines changed
  • app/pages/learn/01_tutorial/04_mastering-the-api/02_modern_io

1 file changed

+40
-44
lines changed

app/pages/learn/01_tutorial/04_mastering-the-api/02_modern_io/index.md

Lines changed: 40 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ This article focuses on tasks that application programmers are likely to encount
55
* Reading and writing text files
66
* Reading text, images, JSON from the web
77
* Visiting files in a directory
8-
* Reading a zip file
8+
* Reading a ZIP file
99
* Creating a temporary file or directory
1010

1111
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,42 +21,39 @@ This article focuses on API improvements since Java 8. In particular:
2121

2222
Tou can read a text file into a string like this:
2323

24-
```
24+
```java
2525
String content = Files.readString(path);
2626
```
2727

2828
Here, `path` is an instance of `java.nio.Path`, obtained like this:
2929

30-
```
30+
```java
3131
var path = Path.of("/usr/share/dict/words");
3232
```
3333

3434
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.
3535

3636
If you want the file as a sequence of lines, call
3737

38-
```
38+
```java
3939
List<String> lines = Files.readAllLines(path);
4040
```
4141

4242
If the file is large, process the lines lazily as a `Stream<String>`:
4343

44-
```
45-
try (Stream<String> lines = Files.lines(path))
46-
{
47-
. . .
44+
```java
45+
try (Stream<String> lines = Files.lines(path)) {
46+
. . .
4847
}
4948
```
5049

51-
Also use `Files.lines` if you can naturally process lines with stream operations (such as `map`, `filter`).
52-
53-
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.
50+
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.
5451

5552
There is no longer a good reason to use the `readLine` method of `java.io.BufferedReader`.
5653

5754
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:
5855

59-
```
56+
```java
6057
Stream<String> tokens = new Scanner(path).useDelimiter("\\PL+").tokens();
6158
```
6259

@@ -68,21 +65,21 @@ Be careful when parsing numbers from text files, since their format may be local
6865

6966
You can write a string to a text file with a single call:
7067

71-
```
68+
```java
7269
String content = . . .;
7370
Files.writeString(path, content);
7471
```
7572

7673
If you have a list of lines rather than a single string, use:
7774

78-
```
75+
```java
7976
List<String> lines = . . .;
8077
Files.write(path, lines);
8178
```
8279

8380
For more general output, use a `PrintWriter` if you want to use the `printf` method:
8481

85-
```
82+
```java
8683
var writer = new PrintWriter(path.toFile());
8784
writer.printf(locale, "Hello, %s, next year you'll be %d years old!%n", name, age + 1);
8885
```
@@ -93,7 +90,7 @@ Weirdly enough, as of Java 21, there is no `PrintWriter` constructor with a `Pat
9390

9491
If you don't use `printf`, you can use the `BufferedWriter` class and write strings with the `write` method.
9592

96-
```
93+
```java
9794
var writer = Files.newBufferedWriter(path);
9895
writer.write(line); // Does not write a line separator
9996
writer.newLine();
@@ -107,32 +104,32 @@ Perhaps the most common reason to use a stream is to read something from a web s
107104

108105
If you need to set request headers or read response headers, use the `HttpClient`:
109106

110-
```
107+
```java
111108
HttpClient client = HttpClient.newBuilder().build();
112109
HttpRequest request = HttpRequest.newBuilder()
113-
.uri(URI.create("https://horstmann.com/index.html"))
114-
.GET()
115-
.build();
110+
.uri(URI.create("https://horstmann.com/index.html"))
111+
.GET()
112+
.build();
116113
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
117114
String result = response.body();
118115
```
119116

120117
That is overkill if all you want is the data. Instead, use:
121118

122-
```
119+
```java
123120
InputStream in = new URI("https://horstmann.com/index.html").toURL().openStream();
124121
```
125122

126123
Then read the data into a byte array and optionally turn them into a string:
127124

128-
```
125+
```java
129126
byte[] bytes = in.readAllBytes();
130127
String result = new String(bytes);
131128
```
132129

133130
Or transfer the data to an output stream:
134131

135-
```
132+
```java
136133
OutputStream out = Files.newOutputStream(path);
137134
in.transferTo(out);
138135
```
@@ -143,14 +140,14 @@ But do you really need an input stream? Many APIs give you the option to read fr
143140

144141
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):
145142

146-
```
143+
```java
147144
URL url = new URI("https://dog.ceo/api/breeds/image/random").toURL();
148145
Map<String, Object> result = JSON.std.mapFrom(url);
149146
```
150147

151148
Here is how to read the dog image from the preceding call:
152149

153-
```
150+
```java
154151
url = new URI(result.get("message").toString()).toURL();
155152
BufferedImage img = javax.imageio.ImageIO.read(url)
156153
```
@@ -165,27 +162,26 @@ The `java.nio.file.Files` class provides a comprehensive set of file operations,
165162

166163
For most situations you can use one of two methods. The `Files.list` method visits all entries (files, subdirectories, symbolic links) of a directory.
167164

168-
```
169-
try (Stream<Path> entries = Files.list(pathToDirectory))
170-
{
171-
. . .
165+
```java
166+
try (Stream<Path> entries = Files.list(pathToDirectory)) {
167+
. . .
172168
}
173169
```
174170

175171
Use a `try`-with-resources statement to ensure that the stream object, which keeps track of the iteration, will be closed.
176172

177173
If you also want to visit the entries of descendant directories, instead use the method
178174

179-
```
175+
```java
180176
Stream<Path> entries = Files.walk(pathToDirectory);
181177
```
182178

183179
Then simply use stream methods to home in on the entries that you are interested in, and to collect the results:
184180

185-
```
181+
```java
186182
try (Stream<Path> entries = Files.walk(pathToDirectory)) {
187-
List<Path> htmlFiles = entries.filter(p -> p.toString().endsWith("html")).toList();
188-
. . .
183+
List<Path> htmlFiles = entries.filter(p -> p.toString().endsWith("html")).toList();
184+
. . .
189185
}
190186
```
191187

@@ -197,29 +193,29 @@ Here are the other methods for traversing directory entries:
197193
* Two `Files.newDirectoryStream` methods yields `DirectoryStream` instances, which can be used in enhanced `for` loops. There is no advantage over using `Files.list`.
198194
* The legacy `File.list` or `File.listFiles` methods return file names or `File` objects. These are now obsolete.
199195

200-
### Working with Zip Files
196+
### Working with ZIP Files
201197

202-
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*:
198+
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*:
203199

204-
```
200+
```java
205201
try (FileSystem fs = FileSystems.newFileSystem(pathToZipFile)) {
206-
. . .
202+
. . .
207203
}
208204
```
209205

210-
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.
206+
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.
211207

212-
You can then use the methods of the `Files` class. Here we get a list of all files in the zip file:
208+
You can then use the methods of the `Files` class. Here we get a list of all files in the ZIP file:
213209

214-
```
210+
```java
215211
try (Stream<Path> entries = Files.walk(fs.getPath("/"))) {
216-
List<Path> filesInZip = entries.filter(Files::isRegularFile).toList();
212+
List<Path> filesInZip = entries.filter(Files::isRegularFile).toList();
217213
}
218214
```
219215

220216
To read the file contents, just use `Files.readString` or `Files.readAllBytes`:
221217

222-
```
218+
```java
223219
String contents = Files.readString(fs.getPath("/LICENSE"));
224220
```
225221

@@ -231,7 +227,7 @@ Fairly often, I need to collect user input, produce files, and run an external p
231227

232228
The calls
233229

234-
```
230+
```java
235231
Path filePath = Files.createTempFile("myapp", ".txt");
236232
Path dirPath = Files.createTempDirectory("myapp");
237233
```
@@ -246,6 +242,6 @@ Web searches and AI chats can suggest needlessly complex code for common I/O ope
246242
2. You may not even need a stream, reader or writer.
247243
3. Become familiar with the `Files` methods for creating, copying, moving, and deleting files and directories.
248244
4. Use `Files.list` or `Files.walk` to traverse directory entries.
249-
5. Use a zip file system for processing zip files.
245+
5. Use a ZIP file system for processing ZIP files.
250246
6. Stay away from the legacy `File` class.
251247

0 commit comments

Comments
 (0)