Java
2022.01.07
JavaのFileクラスでファイル操作!読み込み・書き込み方法まとめ
2023.11.18

プログラムを作る上で、意外によく使うのが「ファイル操作」です。

Javaのプログラム上からも、ファイルの読み書きや移動、削除といったさまざまな操作が可能ですので、それらの方法を紹介していきます。


1.JavaのFileクラスとは?

Javaでは、ファイルを操作するためのクラスとして「File」というクラスが用意されています。

このファイルクラスを使うことで、WindowsやMac、LinuxといったOSの種類を気にせずにファイルを取り扱えます。



2.Fileクラスを使用してファイル操作する方法


まずは、特定のファイルを操作するための方法から紹介します。

①Fileクラスの使い方の基本

コンストラクタの引数にファイルパス(ファイルが格納されている場所)を指定してインスタンスを作成することで、プログラムからファイル操作が可能になります。

File file = new File(ファイルパス);

詳しい操作方法は後述しますが、このファイルインスタンスを操作することで、作成や編集、削除といった操作を行っていきます。

【補足】絶対パスと相対パス

Fileクラスのコンストラクタには、絶対パスまたは相対パスを指定します。


絶対パスは、ルートからみたすべてのフォルダ・ディレクトリを含むパスです。


Windowsの場合、CドライブやDドライブといったドライブからのパスを指します。

C:\Users\<User>\Desktop\Java\test.txt

MacやLinuxの場合、/(スラッシュ)からはじまるパスを指します。

/Users/<User>/Desktop/Java/test.txt

一方で、相対パスはJavaを実行するディレクトリ(カレントディレクトリ)からの相対的な場所を指定します。


カレントディレクトリがデスクトップの場合には、以下の指定を行うことでJavaディレクトリ内にあるtest.txtを読み込むことが可能です。

./Java/test.txt


②ファイルの作成・変更

ここでは、ファイルの作成や変更といった、ファイル自体の操作に関する方法を紹介します。

ファイルの操作を行う場合には、Fileクラスを使用します。

ファイルを新規作成する

ファイルを新規で作成するには、createNewFileメソッドを使用します。

以降のサンプルにおいて、操作するファイルはカレントディレクトリにあるものとし、相対指定を使ってファイルを指定していきます。

import java.io.File;
import java.io.IOException;

public class CreateFile {

    public static void main(String args[]) {
        try{
            File file = new File("./test.txt");
            // 成功した場合にはtrueが返される
            boolean result = file.createNewFile();

            if (result) {
                System.out.println("作成に成功しました");
            } else {
                System.out.println("作成に失敗しました");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}


ファイル名を変更する

ファイル名を変更する場合には、FileクラスのrenameToメソッドを使用します。

// 変更前のファイル
File oldFile = new File("old.txt");
// 変更後のファイル
File newFile = new File("new.txt");

// 変更前のファイルが存在し、かつ変更後のファイルが存在しない場合のみ実行
if(oldFile.exists() && !newFile.exists()) {
    boolean result = oldFile.renameTo(newFile);
    if (result) {
        System.out.println("名前変更に成功しました。");
    } else {
        System.out.println("名前変更に失敗しました。");
    }
}

このとき、変更に失敗した場合にはrenameToメソッドがfalseを返却しますが、なぜ失敗したのかはわからないため注意しましょう。


たとえば、以下のような原因が考えられます。


・変更前のファイルが存在しない

・変更前のファイルが開かれている(ロックされている)

・変更後のファイル名と同名のファイルがすでに存在する


残念ながら、プログラム上からはこれらの原因を確認する方法はありません。失敗した場合には、原因を自分で調べていく必要があるため注意しましょう。

ファイルをコピーする

ファイルをコピーしたい場合には、Filesクラスのcopyメソッドを利用することで、ファイルのコピーを容易かつ安全に実現できます。

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

public class FileCopy{
    
    public static void main (String[] args) {
        try {
            // コピー元とコピー先を指定してコピーを実施
            Files.copy(Paths.get("from.txt"), Paths.get("to.txt"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


③ファイル情報の取得

ファイルの基本的な操作を学んだところで、次はファイルやディレクトリの情報取得方法を紹介します。

ファイルリストを取得する

特定のディレクトリにあるファイルの一覧を取得する方法を紹介します。

// デスクトップの指定(Windowsの場合)
String path = "C:\\Users\\User\\Desktop";

File dir = new File(path);

File[] childFiles = dir.listFiles();
// ファイル名を表示
for (File f : childFiles) {
    System.out.println(f.getName());
}

このコードを実行すると、Fileの引数に指定したディレクトリの中身を順次表示します。

ファイルの拡張子を取得する

次に、ファイルの拡張子を取得する方法を紹介します。


拡張子はファイル名の後ろにある「.(ドット)」以降の単語を指し、ファイルの形式を表しています。


たとえば、Javaの拡張子は 「java」です。


その他、Wordであれば「docx」、Excelであれば「xlsx」といったように、アプリケーションごとに決められた拡張子をつけることで、ダブルクリックだけで適切なアプリケーションを起動できます。

File file = new File("path.txt");

// 指定ファイルがディレクトリでない場合
if (!file.isDirectory()) {
    String ext = file.getName().substring(file.getName().lastIndexOf(".")+1);
    System.out.println(ext);
}

このコードを実行すると、以下のように表示されます。

txt


④ファイルの移動・削除

ファイルの移動や削除も、Javaのコード上で実施することが可能です。


ファイルを移動する

ファイルを移動する場合には、Filesクラスのmoveメソッドを利用することでシンプルに実施できます。

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;

public class FileMove {
    
    public static void main(String[] args) {
        try {
            // 移動先にファイルが存在しても上書きする
            Files.move(Paths.get("old.txt"),
                    Paths.get("./sub/new.txt"), StandardCopyOption.REPLACE_EXISTING);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

引数にPaths.getを用いてファイルパスを2つ指定することで、ファイルの移動を行います。


その際、第3引数にStandardCopyOption.REPLACE_EXISTINGを指定することで、移動先にファイルがあったとしても強制的に上書きをします。


この引数を指定せずに実行したとき、すでに移動先に同名ファイルが存在する場合には移動失敗となります。


強制上書きをしたくない場合には、このオプションを指定しないようにしましょう。

ファイルを削除する

ファイルを削除する場合には、deleteメソッドを利用します。

File target = new File("./del.txt");
boolean result = target.delete();
if (result) {
    System.out.println("削除に成功しました");
} else {
    System.out.println("削除に失敗しました");
}

Javaによりファイルを削除した場合には、ごみ箱には送られず完全削除されます。


実行してしまうとファイル復旧はできませんので、実行する際にはファイルやディレクトリのパスが誤っていないか注意しましょう。

⑤ファイルの詳細を確認

ファイルの中身だけでなく、詳細な情報もJavaのコードから取得可能です。

ファイルやディレクトリが存在するか確認する

ファイルの移動やコピーを実施する際には、existsメソッドを活用することでエラーの発生を抑えることが可能です。


existsメソッドを実行すると、そのファイルまたはディレクトリが存在する場合にはtrueが、存在しない場合にはfalseが返却されます。

File target = new File("./hello.txt");

if(target.exists()) {
    // 削除処理
    target.delete();
} else {
    System.out.println("ファイルが存在しません");
}

existsを活用することで、ファイルが存在しない時に発生するIOExceptionがスローされることを防げます。

ファイルの読み込み・書き込みが可能か判定する

Fileでは、canReadやcanWriteを利用することで、そのファイルの読み書きに関する情報を操作できます。

File target = new File("write.txt");

// 書き込み権限チェック
boolean canRead = target.canRead();
// 読み込み権限チェック
boolean canWrite = target.canWrite();

if(canRead && canWrite) {
    System.out.println("読み書き可能です");
} else if (canWrite) {
    System.out.println("書き込みのみ可能です");
} else if (canRead) {
    System.out.println("読み込みのみ可能です");
} else {
    System.out.println("読み込みも書き込みもできません");
}


⑥ファイルの読み込み・書き込み

ファイルに対してデータを書き込む方法を紹介します。


ファイルの中身を扱う場合には、FileInputStreamやFileOutputStreamを利用します。
実際にファイルを読み込む・書き込む場合の処理を見ていきましょう。

ファイルを読み込む

Javaでファイルの内容を読み込む方法はいくつかあるため、目的に応じて使い分けると良いでしょう。

まずは、ファイルの中身をすべて読み込み、文字列として格納する方法を紹介します。

// 書き込むファイルパスの例
String path = "C:\\Users\\User\\Desktop\\read.txt";

try(FileInputStream stream = new FileInputStream(path)) {
    // ファイルのデータをすべて読み込む
    byte[] bytes = stream.readAllBytes();
    // データを文字列として格納
    String allString = new String(bytes);
}catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

テキストのファイルを読み込む場合には、1行ずつ読み込みたい場合もあります。

その場合には、BufferedReaderを利用しましょう。

// 書き込むファイルパスの例
String path = "C:\\Users\\User\\Desktop\\read.txt";

try(FileReader fr = new FileReader(path);
    BufferedReader br = new BufferedReader(fr)){

    // 1行目を読み込む
    String line = br.readLine();
    System.out.println(line);
    
    // 2行目を読み込む
    String next = br.readLine();
    System.out.println(next);

}catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

このとき、br.readLine()を実行するたびに次の行が読み込まれます。

1行ずつ順番に読み込む必要がある場合には、BufferedReaderを利用すると良いでしょう。

ファイルに書き込む

ファイルにテキストを書き込みたい場合には、OutputStreamWriterを利用します。

// 書き込むファイルパスの例
String path = "C:\\Users\\User\\Desktop\\write.txt";

try(FileOutputStream stream = new FileOutputStream(path);
    OutputStreamWriter writer = new OutputStreamWriter(stream);){

    // 文字列の書き込み
    writer.write("This is a sample file.");

} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

これで、「This is a sample file.」と記載されたファイルがデスクトップに生成されます。

⑦ファイルを閉じる

ファイルに書き込みを行った場合には、「ファイルを閉じる」という手順が必要です。


ファイルを閉じ忘れると、そのファイルがロックされたままになってしまい、他のアプリケーションで編集ができなくなります。


そのため、本来であれば以下のような処理を実装する必要があります。

FileOutputStream stream;
OutputStreamWriter writer;
try{
    stream = new FileOutputStream(path);
    writer = new OutputStreamWriter(stream);

    writer.write("This is a sample file.");

} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    writer.close();
    stream.close();
}

ただし、FileOutputStreamとOutputStreamWriterの宣言をtryの中に記載することで、自動でclose()を呼び出してくれます。


この機能を実現するのが「try-with-resource」です。


以下のように、tryのうしろの()中に変数宣言をすることで、tryの中のブロック({〜}の間の処理)が終了した時点で、自動的にcloseを呼び出してくれます。

try(FileOutputStream stream = new FileOutputStream(path);
    OutputStreamWriter writer = new OutputStreamWriter(stream);){

try-with-resourceを活用することでclose()の実行忘れを防げるため、積極的に活用していきましょう。



3.ファイル操作する際の注意点  

ファイルを操作する場合には、以下の点に気をつけましょう。

①文字コードに気をつける

WindowsはShift-JIS、LinuxやMacはUTF-8という文字コードを採用しており、同じテキストファイルであっても中身のバイトデータは異なります。


Javaのプログラムで「こんにちは」と書き込んだテキストを開いたのに、テキストエディタ上には「縺薙s縺ォ縺。縺ッ」という文字が表示される。というような経験をしたことがある方も多いのではないでしょうか。


このような現象を「文字化け」と呼びます。


この文字化けの問題は、主にWindowsで作成したファイルを読み込む場合に発生しやすく、よく目にするのが「Excelで作成したCSVファイルの読み込み」です。


Excelで作成したファイルはShift-JISですが、Javaで読み込んだ際にUTF−8として認識されてしまい、結果として文字化けしてしまうことがあります。

文字コードを明記する

もし文字化けが発生する場合には、文字コードを明記するようにしましょう。


InputStreamReaderを利用して文字コードを指定することで、文字コードを利用したファイル読み込みが可能です。

try(FileInputStream fs = new FileInputStream(path);
    InputStreamReader fr = new InputStreamReader(fs,"Shift-JIS");
    BufferedReader br = new BufferedReader(fr)){

    // 読み込み処理は省略

}catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}


②ファイルの存在状態を確認する

システム開発でファイルを操作するプログラムを作成した場合に、エラーの原因の多くを占めるのが「ファイルの存在チェック」です。


例として、プログラムAで作成したファイルを、プログラムBで読み込んで使用するような場合を考えます。


プログラムAの実行が終了してからプログラムBを実行すれば問題ないのですが、プログラムAの実行が終わる前にプログラムBが実行されるとどうなるでしょうか。


その場合、読み込むファイルが存在しないためエラーが発生して異常終了してしまいます。


このような問題は、大量のデータを操作する「バッチ処理」で特に多く発生するバグです。

ファイルの存在を事前にチェックする

ファイルを取り扱う場合には、事前にexistsメソッドを利用してファイルが存在するかを確認しましょう。


事前にファイルの存在を確認することで、予期しないエラーの発生を未然に防げます。

ファイルの読み書きは、プログラムの外部にあるデータを取り扱うため、実行時に何が起きるかわかりません。


ファイルを操作するプログラムを作成する際には、


・作成や移動をする場合、同名ファイルがあったらどうするか?

・コピーする場合に元のファイルが存在しなかったらどうするか?

・読み込みたいファイルが存在しなかったらどうするか?


といったパターンをあらかじめ想定し、プログラミングすることが大切です。


この記事をシェア