Historically, Java's file I / O process was notorious for being cumbersome. Java's file I / O processing was often the target of attacks when the scripting language camp appealed its high "productivity". It is said that the processing that can be realized in a few lines in a script language becomes dozens of lines in Java.
Time has passed, and the java.nio.file
package (NIO2 File API) and try-with-resources syntax introduced in Java 7 in 2011 have greatly improved the situation. Now, even Java can realize file input / output processing with the same amount of code as the scripting language.
However, in articles that search for "Java file I / O" and hit the top, only inappropriate code that uses only the API before the above improvements were introduced is conspicuous. Therefore, in this article, I would like to systematically and concisely summarize the simplest Java file input / output processing that beginners should know at the moment, regardless of the historical background of the past.
The java.nio.file.Path
interface (reference: Javadoc is used to represent the path of the file system. Use /Path.html)). There are various ways to create a Path instance, but in reality, the java.nio.file.Paths
utility class (Reference: Javadoc Mostly generated using java / nio / file / Paths.html)).
Path path = Paths.get("items.csv");
The path string can be specified as either a relative path or an absolute path.
Path path = Paths.get("/etc/passwd");
Considering the portability of path-delimited strings, it is better to use this variable-length argument.
Path path = Paths.get("/etc", "passwd");
Starting with Java 11, the Path.of (String)
method was introduced in addition to the Paths.get (String)
method (Reference: Javadoc javase / 11 / docs / api / java.base / java / nio / file / Path.html # of (java.lang.String, java.lang.String ...))). The functionality is the same, but this one is more consistent with List.of ()
Map.of ()
etc., which was also introduced in Java 11, and is more natural.
Path path = Path.of("items.csv");
File-related processing is done with the Path
interface and the java.nio.file.Files
utility class (Reference: Javadoc Combine nio / file / Files.html)). For example, it looks like this.
List<String> lines = Files.readAllLines(Paths.get("items.csv"));
As a class that represents a file in Java, java.io.File
(Reference: Javadoc )) You might think of it. This is an older method and can be replaced by the functionality of the java.nio.file
package. Note that if the old API only accepts java.io.File
instead of java.nio.file.Path
, you can convert between Path # toFile ()
and File # toPath ()
.
In this article, we won't go into the details of what a text binary is, but simply read and write a file of type String
from Java's perspective as a text file.
The simplest way to read text is with the Files.readString (Path)
method. This method returns the entire contents of the file as a String.
String content = Files.readString(Paths.get("items.csv"));
You need to be careful about the character set when reading and writing text. The above code does not specify the character set, so the default UTF-8 is used. The method of specifying the character set is shown below.
String content = Files.readString(Paths.get("items.csv"), StandardCharsets.UTF_8);
String content = Files.readString(Paths.get("items.csv"), Charset.forName("MS932"));
Well, here is one unfortunate news. The Files.readString (Path)
Files.readString (Path, Charset)
method described above is only available in Java 11 and above. Here's another way you can use it from java 7. This method returns the contents of the file as a List <String>
type.
List<String> lines = Files.readAllLines(Paths.get("items.csv"), StandardCharsets.UTF_8);
If the file size is small, you can read them all at once as described above. However, if you have the opportunity to process files larger than tens or hundreds of megabytes, you should remember how to handle them with Stream <String>
here. This method has better performance.
try (Stream<String> lines = Files.lines(Paths.get("items.csv"), StandardCharsets.UTF_8)) {
lines.forEach(line -> System.out.println(line));
} catch (IOException e) {
throw new UncheckedIOException(e);
}
When using this method, use the try-with-resources syntax to prevent forgetting to close. The same applies to reading and writing of other subdivisions. For more information, see Java Exception Handling in a Step-by-Step Understanding (https://qiita.com/ts7i/items/d7f6c1cd5a14e55943d4).
Also, if you need to read subdivided text that is not line-oriented, java.io.BufferedReader
returned fromFiles.newBufferedReader (Path, Charset)
(Reference: Javadoc Use com / javase / jp / 8 / docs / api / java / io / BufferedReader.html)). If you want to read a huge JSON file without line breaks, you will need this method.
try (BufferedReader in = Files.newBufferedReader(Paths.get("items.csv"), StandardCharsets.UTF_8)) {
for (int ch = 0; (ch = in.read()) > 0;) {
System.out.print((char) ch);
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
Further abstraction when combined with java.util.Scanner
(Reference: Javadoc) High API can be used.
try (BufferedReader in = Files.newBufferedReader(Paths.get("items.csv"), StandardCharsets.UTF_8);
Scanner sc = new Scanner(in)) {
sc.useDelimiter("(,|\\n)");
while (sc.hasNext()) {
System.out.println(sc.next());
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
The simplest way to write text is with the Files.writeString (Path, CharSequence, OpenOption ...)
method. This method writes the entire contents of the given CharSequence
to a file. Note that String
and StringBuilder
are a type of CharSequence
(Reference: [Javadoc](https://docs.oracle.com/javase/jp/8/docs/api/java/lang/CharSequence. html)).
String content = "0-0\t0-1\t0-2\n1-0\t1-1\t1-2\n";
Files.writeString(Paths.get("items.tsv"), content);
You can add it by setting ʻOpenOption`.
String content = "0-0\t0-1\t0-2\n1-0\t1-1\t1-2\n";
Files.writeString(Paths.get("items.tsv"), content, StandardOpenOption.APPEND);
You can specify the character set here as well as when reading.
String content = "0-0\t0-1\t0-2\n1-0\t1-1\t1-2\n";
Files.writeString(Paths.get("items.tsv"), content, StandardCharsets.UTF_8);
String content = "0-0\t0-1\t0-2\n1-0\t1-1\t1-2\n";
Files.writeString(Paths.get("items.tsv"), content, Charset.forName("MS932"));
Now, here is another unfortunate news. The above Files.writeString (Path, CharSequence, OpenOption ...)
Files.writeString (Path, CharSequence, Charset, OpenOption ...)
method is only available in Java 11 and above. Before that, you can only use the same method as writing in small pieces.
When writing text in small pieces, java.io.BufferedWriter
returned fromFiles.newBufferedWriter (Path, Charset, OpenOption ...)
(Reference: Javadoc /jp/8/docs/api/java/io/BufferedWriter.html)) is used.
List<String> lines = new ArrayList<String>();
...
try (BufferedWriter out = Files.newBufferedWriter(Paths.get("items.tsv"), StandardCharsets.UTF_8)) {
for (String line : lines) {
out.write(line);
out.newLine();
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
In this article, a file that is read and written as a byte string from the perspective of Java is simply called a binary file.
The simplest way to read a binary is the Files.readBytes (Path)
method. This method returns the entire contents of the file as byte []
.
byte[] content = Files.readAllBytes(Paths.get("selfie.jpg "));
For reference, the method of converting from byte []
to String
or java.io.InputStream
is shown below. Such conversion is necessary depending on the convenience of the API to which the loaded binary is passed.
byte[] content = Files.readAllBytes(Paths.get("items.csv"));
String contentAsString = new String(content, StandardCharsets.UTF_8);
byte[] content = Files.readAllBytes(Paths.get("selfie.jpg "));
InputStream in = new ByteArrayInputStream(content);
As with text, bulk loading is not recommended for large file sizes. Instead, the Files.newInputStream (Path, OpenOption ...)
method returns java.io.InputStream
(Reference: Javadoc /api/java/io/InputStream.html))) is used. Regarding the acquired java.io.InputStream
, there are more cases where it is processed by an existing library than when it is processed by turning a loop on its own. As an example, the following code passes it to Apache POI.
try (InputStream in = Files.newInputStream(Paths.get("items.xlsx"))) {
XSSFWorkbook book = new XSSFWorkbook(in);
...
} catch (IOException e) {
throw new UncheckedIOException(e);
}
The simplest way to write a binary is the Files.write (Path, byte [], OpenOption ...)
method.
byte[] content = ...;
Files.write(Paths.get("selfie.jpg "), content);
When writing binaries in small pieces, java.io.OutputStream
returned fromFiles.newOutputStream (Path, OpenOption ...)
(Reference: Javadoc / 8 / docs / api / java / io / OutputStream.html))) is used. There will be more cases where the existing library handles this as well, rather than handling it yourself. As an example, the following code passes it to Apache POI.
Item item = ...;
try (OutputStream out = Files.newOutputStream(Paths.get("items.xlsx"))) {
XSSFWorkbook book = new XSSFWorkbook();
...
book.write(out);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
Below is an example of code that was common in the days when there was neither NIO2 File API nor try-with-resources. Certainly, this is a complexity that cannot be complained even if attacked by the scripting language camp. Regarding the multi-stage try-catch part, "Originally, if you close BufferedReader
, the lower level ʻInputStream will also be closed, but if you fail to initialize
BufferedReader`, a resource leak may occur. I remember that there was an argument such as "It is necessary for ...". I've forgotten the details, and I don't think I need to remember them anymore.
String content = null;
InputStream is = null;
try {
is = new FileInputStream("items.csv");
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = br.readLine()) != null) {
sb.append(line);
sb.append(System.lineSeparator());
}
content = sb.toString();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
if (br != null) {
br.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
} catch (IOException e) {
new RuntimeException(e);
} finally {
try {
if (is != null) {
is.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
Again, what you're trying to do with the code above can now be achieved with:
String content = Files.readString(Paths.get("items.csv"));
Recommended Posts