-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathStreamFileIO.java
More file actions
147 lines (132 loc) · 5.58 KB
/
Copy pathStreamFileIO.java
File metadata and controls
147 lines (132 loc) · 5.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package Phase5_CollectionsLambdasStreams.LambdaAndStreams;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Streams + File I/O (java.nio.file.Files)
* ----------------------------------------
* The java.nio.file.Files class exposes several stream-returning methods.
* They let you process files with the same declarative style you use for
* collections - and crucially they STREAM lazily, so you can process a
* multi-gigabyte file with a tiny memory footprint.
* <p>
*
* Stream-Returning Methods on Files
* ---------------------------------
* Files.lines(Path) Stream<String> - one element per line
* Files.lines(Path, Charset)
* Files.list(Path) Stream<Path> - children of one dir
* Files.walk(Path[, maxDepth]) Stream<Path> - recursive tree walk
* Files.find(Path, depth, biPredicate) recursive with a filter
* <p>
*
* Why You Should Use try-with-resources
* -------------------------------------
* These streams hold OS handles (file descriptors). They implement
* AutoCloseable; ALWAYS wrap them in try-with-resources so the handle is
* released even if the pipeline throws.
* <p>
*
* try (Stream<String> lines = Files.lines(path)) {
* lines.filter(...).forEach(...);
* }
* <p>
*
* Writing Files - the Counterpart
* -------------------------------
* Files.write(Path, Iterable<String>) - whole file at once
* Files.write(Path, byte[], OpenOption...)
* Files.writeString(Path, CharSequence) Java 11+
* Files.newBufferedWriter(Path) streamable BufferedWriter
* <p>
*
* Demo Below
* ----------
* We write a small CSV-like file in /tmp (or the OS temp dir), read it
* back as a Stream, do a couple of analyses, then delete the file.
*/
public class StreamFileIO {
public static void main(String[] args) throws IOException {
section("1) Write a sample file");
Path file = Files.createTempFile("hellojava-stream-", ".csv");
Files.write(file, List.of(
"name,dept,salary",
"Alice,ENG,90000",
"Bob,ENG,85000",
"Carol,PM,110000",
"Dave,ENG,95000",
"Eve,PM,105000",
"Fran,HR,80000"
), StandardCharsets.UTF_8);
System.out.println("wrote " + file);
section("2) Files.lines - process line by line as a Stream");
try (Stream<String> lines = Files.lines(file)) {
long count = lines.skip(1).count(); // skip header
System.out.println("data rows = " + count);
}
section("3) Stream pipeline against the file");
try (Stream<String> lines = Files.lines(file)) {
double engTotal = lines
.skip(1)
.map(s -> s.split(","))
.filter(cols -> cols[1].equals("ENG"))
.mapToDouble(cols -> Double.parseDouble(cols[2]))
.sum();
System.out.println("total ENG salary = " + engTotal);
}
section("4) Group by department via Collectors");
try (Stream<String> lines = Files.lines(file)) {
Map<String, List<String>> byDept = lines
.skip(1)
.map(s -> s.split(","))
.collect(Collectors.groupingBy(
cols -> cols[1],
Collectors.mapping(cols -> cols[0], Collectors.toList())));
byDept.forEach((d, names) -> System.out.println(d + " -> " + names));
}
section("5) Files.list - children of one directory (top-level only)");
Path parent = file.getParent();
try (Stream<Path> kids = Files.list(parent)) {
long count = kids
.filter(p -> p.getFileName().toString().startsWith("hellojava-stream-"))
.count();
System.out.println("temp files matching prefix = " + count);
}
section("6) Files.walk - recursive walk (BFS-like) - depth 1 only here");
try (Stream<Path> walk = Files.walk(parent, 1)) {
walk.limit(5).forEach(p -> System.out.println(" " + p.getFileName()));
}
section("7) Writing - append more rows with newBufferedWriter");
try (var bw = Files.newBufferedWriter(file,
StandardCharsets.UTF_8,
StandardOpenOption.APPEND)) {
bw.write("Greg,HR,82000");
bw.newLine();
bw.write("Hank,PM,108000");
bw.newLine();
}
try (Stream<String> lines = Files.lines(file)) {
System.out.println("rows after append = " + lines.count());
}
section("8) Files.writeString (Java 11+) - quick whole-file write");
Path notes = Files.createTempFile("hellojava-stream-notes-", ".txt");
Files.writeString(notes, "first line\nsecond line\n");
try (Stream<String> lines = Files.lines(notes)) {
lines.forEach(s -> System.out.println(" read: " + s));
}
section("9) Cleanup");
Files.deleteIfExists(file);
Files.deleteIfExists(notes);
System.out.println("temp files deleted");
// OUTPUT (file paths vary by OS)
}
private static void section(String title) {
System.out.println("\n====== " + title + " ======");
}
}