これまでの記事では、変数や配列、ArrayListなどを使ってデータを管理してきました。
しかし、プログラムを終了すると、変数などに保存していたデータは通常、そのままでは次回の実行に引き継がれません。
例えば、受講者の名前や商品の情報を保存し、次回のプログラム実行時にも利用したい場合は、ファイルにデータを書き込む方法があります。
Javaでは、テキストファイルなどにデータを書き込んだり、ファイルからデータを読み込んだりできます。
今回は、Java 17で利用できるPath・Filesクラスを使って、基本的なファイル操作を学習しましょう。
Pathは、ファイルやディレクトリの場所を表すための型です。
例えば、次のコードを見てみましょう。
import java.nio.file.Path;
Path path = Path.of("memo.txt");
このコードでは、memo.txtというファイルのパスを表すPathオブジェクトを作成しています。
ここでは、ファイル名だけを指定しているため、相対パスとして扱われます。実際にどの場所のファイルを指すかは、プログラムの実行時の作業ディレクトリによって決まります。
Pathはファイルの場所を表すものであり、このコードだけでファイルが作成されるわけではありません。
ファイルへの書き込みには、FilesクラスのwriteString()メソッドを利用できます。
まずは、文字列をファイルに保存してみましょう。
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class Main {
public static void main(String[] args) {
Path path = Path.of("memo.txt");
try {
Files.writeString(path, "Javaの学習を始めました。");
System.out.println("ファイルに書き込みました。");
} catch (IOException e) {
System.out.println("ファイルの書き込みに失敗しました。");
}
}
}
ファイルに書き込みました。
正常に処理された場合、実行時の作業ディレクトリにmemo.txtが作成され、次の文字列が保存されます。
Javaの学習を始めました。
writeString()は、指定したパスのファイルが存在しない場合は新しく作成し、存在する場合は既存の内容を置き換えるのが基本の動作です。
そのため、既存のファイルに内容を追加したい場合は、後述するように追加モードを指定する必要があります。
先ほどのコードでは、catchにIOExceptionを指定していました。
catch (IOException e) {
System.out.println("ファイルの書き込みに失敗しました。");
}
IOExceptionは、入出力処理で問題が発生した場合に使われる例外です。
ファイル操作では、次のような問題が起こる可能性があります。
ファイル操作でIOExceptionが発生する可能性があるため、try・catchなどで対応します。
ただし、すべてのファイル操作の失敗がIOExceptionになるわけではありません。例えば、不正なパスなど、別の例外が発生する場合もあります。
次は、ファイルに保存した文字列を読み込んでみましょう。
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class Main {
public static void main(String[] args) {
Path path = Path.of("memo.txt");
try {
String text = Files.readString(path);
System.out.println(text);
} catch (IOException e) {
System.out.println("ファイルの読み込みに失敗しました。");
}
}
}
このプログラムでは、readString()を使ってファイルの内容を文字列として読み込みます。
memo.txtに「Javaの学習を始めました。」と保存されている場合、実行結果は次のようになります。
Javaの学習を始めました。
読み込むファイルが存在しない場合などはIOExceptionが発生する可能性があるため、例外処理を行っています。
ファイルへの書き込みと読み込みを組み合わせると、保存したデータを再び利用できます。
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class Main {
public static void main(String[] args) {
Path path = Path.of("memo.txt");
try {
Files.writeString(path, "商品A\n商品B\n商品C");
String text = Files.readString(path);
System.out.println(text);
} catch (IOException e) {
System.out.println("ファイル操作に失敗しました。");
}
}
}
商品A
商品B
商品C
この例では、最初に3つの商品名をファイルに書き込み、そのあとで同じファイルから読み込んで表示しています。
書き込み → 保存 → 読み込みという流れを確認しておきましょう。
日本語を含むテキストファイルを扱う場合は、文字コードも重要です。
文字コードとは、文字をコンピュータで扱うための符号化方式です。読み書きする際の文字コードが合っていないと、文字化けが発生することがあります。
Javaでは、StandardCharsets.UTF_8を使ってUTF-8を明示できます。
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
public class Main {
public static void main(String[] args) {
Path path = Path.of("memo.txt");
try {
Files.writeString(
path,
"こんにちは",
StandardCharsets.UTF_8
);
String text = Files.readString(
path,
StandardCharsets.UTF_8
);
System.out.println(text);
} catch (IOException e) {
System.out.println("ファイル操作に失敗しました。");
}
}
}
こんにちは
書き込みと読み込みの両方でUTF-8を指定しています。
Java 17のwriteString()とreadString()は、文字コードを省略した場合もUTF-8を使用しますが、文字コードを明示すると意図が分かりやすくなります。
writeString()は、通常、既存ファイルの内容を置き換えます。
すでに保存されている内容を残しながら、新しい文字列を追加したい場合は、StandardOpenOption.APPENDを利用します。
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
public class Main {
public static void main(String[] args) {
Path path = Path.of("memo.txt");
try {
Files.writeString(
path,
"新しいデータ\n",
StandardCharsets.UTF_8,
StandardOpenOption.CREATE,
StandardOpenOption.APPEND
);
System.out.println("データを追加しました。");
} catch (IOException e) {
System.out.println("書き込みに失敗しました。");
}
}
}
この例では、ファイルが存在しない場合は作成し、存在する場合は既存の内容の末尾に文字列を追加します。
改行を入れたい場合は、文字列の末尾に「\n」を指定できます。
ファイル操作でよくある問題の一つが、ファイルの場所を間違えることです。
Path path = Path.of("memo.txt");
このようにファイル名だけを指定すると、実行時の作業ディレクトリを基準にファイルが扱われます。
そのため、ファイルが見つからない場合は、次の点を確認しましょう。
ファイル操作では、プログラムのコードだけでなく、ファイルの保存場所も確認することが大切です。
ファイル操作では、ファイルを開いたあとに適切に閉じる必要がある場合があります。
Javaには、リソースの終了処理を自動化するtry-with-resourcesという仕組みがあります。
例えば、Files.newBufferedReader()を利用する場合は、次のように書けます。
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
public class Main {
public static void main(String[] args) {
Path path = Path.of("memo.txt");
try (BufferedReader reader =
Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
System.out.println("ファイルの読み込みに失敗しました。");
}
}
}
このコードでは、ファイルを1行ずつ読み込み、内容を表示しています。
tryの後ろの丸括弧内でBufferedReaderを作成しています。tryブロックを抜けると、BufferedReaderは自動的に閉じられます。
これにより、ファイルを閉じ忘れるリスクを減らせます。
今回のようなテキストファイルの読み書きではreadString()やwriteString()を使う方法もありますが、ファイルを1行ずつ処理したい場合などにはBufferedReaderが便利です。
writeString()は、通常、既存のファイルの内容を置き換えます。末尾に追加したい場合は、APPENDなどのオプションを指定します。
相対パスは、プログラムの実行時の作業ディレクトリを基準に解決されます。想定した場所にファイルができない場合は、作業ディレクトリを確認しましょう。
ファイルの読み書きでは、IOExceptionが発生する可能性があります。try・catchなどで適切に対応しましょう。
異なる文字コードで読み書きすると、文字化けの原因になることがあります。必要に応じてUTF-8などを明示しましょう。
ファイル操作を覚えると、プログラムで扱ったデータをファイルに保存し、あとから再利用できるようになります。
これまで学んだ変数・配列・繰り返し・例外処理などと組み合わせることで、より実用的なプログラムを作ることができます。
次回は、処理を簡潔に記述するためのラムダ式について学習します。