Javaプログラミングで、ファイル出力は必須の技術だ。
データベースを使えない際のデータ保存や、ユーザ利便性のためのCSV出力など様々な場面で活躍する。
このページではJavaのファイル出力方法についてまとめた。ファイル出力方法を調べている方には参考になるだろう。
目次
Javaによるファイル出力の基本
Javaに限らず、どんなプログラム言語であっても、ファイル出力処理の流れはほとんど変わらない。次の流れだ。
- ファイルを開く
- ファイルの中身を書き込む
- ファイルを閉じる
例えば、ファイルに文字を出力する処理を最もシンプル記述すると、以下のようになる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import java.io.FileWriter; import java.io.IOException; public class Main { public static void main(String[] args) { try { FileWriter fw = new FileWriter("test.txt"); fw.write("テスト"); fw.close(); } catch (IOException ex) { ex.printStackTrace(); } } } |
この例では
- 7行目:ファイルを開く
- 8行目:ファイルの中身を書き込む
- 9行目:ファイルを閉じる
となっている。
それぞれの記述について、もう少し細かく説明しよう。
ファイルを開く
FileWriterクラスのオブジェクトを生成すると、同時に「ファイルを開く」という処理が行われている。
ファイルが存在しない場合は、新しくファイルが作成される。
ファイルを開く際には「書き込みのために開く」という処理が行われているため、何らかの理由で「書き込みのために」開くことが出来なかった場合には、IOExceptionが発生する。
「書き込みのために」開くことが出来ないとは、他のプログラムですでに開いている場合や、読み取り専用のファイルの場合などがある。
ファイルの中身を書き込む
ここでは「テスト」という文字列をファイルに書き込んでいる。
「書き込んでいる」と言っても、この段階ですでにファイルに出力されている訳では無い。実際にファイルに出力されるのは、9行目の「fw.close()」を実行してからになる。
また、書き込まれる文字列は、「UTF-8」という文字コードになる。これはJavaで標準的に扱われる文字コードであり、その他の文字コードでファイルに書き込みたい場合には、文字コードの変換処理が必要になる。
ファイルを閉じる
この処理を実行すると、実際のファイルに文字列が書き込まれ、ファイルが閉じられる。
上でも説明したが、この処理を行うまではファイルには何も出力されていない。処理の途中で実際のファイルに出力する方法は、後ほど紹介する。
ここまでが最もシンプルなファイル出力の方法だ。Javaでファイル出力を行う方法は他にもある。以下に、ファイル出力に関連するクラスを紹介しよう。
Javaファイル出力に関するクラスたち
FileWriterクラス
まず、前述のサンプルで使用されているFileWriterを理解しよう。
ファイルを開く、書き込む、閉じるはすでに説明したが、もう一つの使い方として、「ファイルの追記」がある。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import java.io.FileWriter; import java.io.IOException; public class Main { public static void main(String[] args) { try { FileWriter fw = new FileWriter("test.txt",true); fw.write("テスト"); fw.close(); } catch (IOException ex) { ex.printStackTrace(); } } } |
7行目に注目してほしい。
FileWriterを生成するコンストラクタの第2引数に「true」を渡している。これは「追加」を意味する引数だ。
実際にこのプログラムを実行してみるとわかるが、先ほどのサンプルの場合は「テスト」と1文だけ記載されたファイルが作成されるのに対し、この例では1回実行するたびに「テスト」という文字列が増えていくのがわかるだろう。
これは、FileWriterが追記の為にファイルを開いているからであり、すでに書き込まれているファイルの一番後ろから書き始めている事を意味している。
但し、この方法の場合、すでに書き込まれている内容とは無関係な処理を行う場合にしか利用できない。
例えば、すでに記述されている内容に応じて、次に追記する内容を変えたり、文章の途中を書き換えたりする場合には、後述のRandomAccessFileを使用する。
PrintWriterクラス
前述のFileWriterとほぼ同じような使い方だたが、出力文字列の整形など、テキスト出力に特化した機能がある。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import java.io.IOException; import java.io.PrintWriter; public class Main7 { public static void main(String[] args) { try { PrintWriter pw = new PrintWriter("test.txt"); pw.println("テスト"); pw.close(); } catch (IOException ex) { ex.printStackTrace(); } } } |
上記の例を実行すると、先ほどと同じように「test.txt」が作成される。ファイルに記載されている内容も「テスト」と変わったところは見られない。
しかし、それぞれの作成されたファイルを見比べると一つだけ違う点がある。それは「テスト」という文字列の後ろに改行が有るかどうかだ。
FileWriterで出力した際には改行が無いのだが、PrintWriterで出力した際には改行が追加されている。
これは、クラスの違いというより、PrintWriterのprintlnメソッド(サンプル8行目)の性質によるものだ。
PrintWriterクラスには、出力する際の文字列に整形を加える機能を持ったメソッドが用意されている。
以下はprintf()メソッドを利用した例だ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import java.io.IOException; import java.io.PrintWriter; public class Main8 { public static void main(String[] args) { try { PrintWriter pw = new PrintWriter("test.txt"); int a = 3,b = 5 ; pw.format("a + b = %d + %d = %d", a, b, a+b); pw.close(); } catch (IOException ex) { ex.printStackTrace(); } } } |
実行してみるとわかるが、test.txtには
a + b = 3 + 5 = 8
と記述されている。
Fileクラス
ファイル操作を行う処理の最も基本的なクラスだ。
ファイル出力前に、そのファイルが既に存在しているかどうかを確認したり、ファイルを移動(別名に変更)させたりすることが出来る。
また、ファイル以外にフォルダを扱うことも出来る。
ファイルの存在を確認する例
1 2 3 4 5 6 7 8 9 10 11 12 |
import java.io.File; public class Main { public static void main(String[] args) { File file = new File("test.txt"); if(file.exists()){ System.out.println("ファイルは存在します"); }else{ System.out.println("ファイルは存在しません"); } } } |
よく使うメソッド
exists() |
ファイルまたはフォルダが存在するかどうかを判定する |
delete() |
ファイルまたはフォルダを削除する |
getAbsolutePath() |
このファイルのフルパス(フォルダ名を含んだパス)を取得する |
isDirectory() |
このオブジェクトがフォルダを示す場合はtrue |
isFile() |
このオブジェクトがファイルを示す場合はtrue |
list() |
このオブジェクトがフォルダを示す場合は、そのフォルダに含まれるファイルの一覧 |
renameTo(File dest) |
ファイル名の変更(またはファイルの移動) |
length() |
ファイルサイズを取得する |
以下のように、Fileクラスを使用してFileWriterの生成することもできる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import java.io.File; import java.io.FileWriter; import java.io.IOException; public class Main { public static void main(String[] args) { try { File file = new File("test.txt"); FileWriter fw = new FileWriter(file); fw.write("テスト"); fw.close(); } catch (IOException ex) { ex.printStackTrace(); } } } |
FileOutputStreamクラス
FileWriterクラスは主にテキストファイルを出力するときに使用するが、こちらは画像ファイルやExcel/Wordのようなバイナリファイルを出力するときに使用する。
以下に、バイナリファイルをコピーする例を示す。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import java.io.FileInputStream; import java.io.FileOutputStream; public class Main { public static void main(String[] args) { try { FileInputStream fis = new FileInputStream("input.png"); FileOutputStream fos = new FileOutputStream("output.png"); int c = 0 ; while((c = fis.read()) != -1){ fos.write(c); } fis.close(); fos.close(); } catch (Exception e) { e.printStackTrace(); } } } |
ファイルの読み込み処理も入っているので少し複雑に感じるかも知れないが、処理内容は以下の通りだ
- 8行目:ファイルを読み込みのために開く(「input.png」を開く)
- 9行目:ファイルを書き込みのために開く(「output.png」を開く)
- 11行目:「input.png」から1バイトだけ読み込む
- 12行目:「output.png」に1バイトだけ書き込む
- 11行目~12行目を、ファイルの全バイト分繰り返す(-1が帰ってきたら終わり)。
- 14行目:「input.png」を閉じる
- 15行目:「output.png」を閉じる
この例では1バイトずつ読み込み/書き込みを繰り返しているが、ある程度まとまった単位で読み書きするためのメソッドも用意されている。
プログラムが利用可能なメモリの量に応じて、1Kバイト~1Mバイト程度の単位で読み書きを行ったほうが効率が良いだろう。
OutputStreamWriterクラス
最初に紹介した方法では、UTF-8という文字コードでファイルが作成されると説明したが、実際のプログラムでは、他の文字コードで出力したいというケースも出てくるだろう。
そんな時に利用するのがOutputStreamWriterクラスだ。
OutputStreamWriterを利用して、文字コードをShift_JISで出力する例を紹介する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; public class Main { public static void main(String[] args) { try { FileOutputStream fos = new FileOutputStream("test.txt"); OutputStreamWriter osw = new OutputStreamWriter(fos,"Shift_JIS"); osw.write("テスト"); osw.close(); fos.close(); } catch (IOException ex) { ex.printStackTrace(); } } } |
注目すべきは、9行目から10行目にかけての処理だ。
OutoputStreamWriterを生成する際に、FileOutputStreamと文字コード「Shift_JIS」を指定している。
これは、OutoputStreamWriterが「Shift_JIS」に文字変換を行いつつ、FileOutputStreamに対して変換後の文字列を出力するという意味だ。
FileOutputStreamはファイルに書き込むための通り道を表しており、OutoputStreamWriterはその通り道上で文字コードを変換するためのフィルタのようなものと理解すれば良いだろう。
Javaで作成するプログラムは、複数の文字コードを扱うことも多い。その為、この例のように、文字コードの変換処理が必要なケースも少なくない。
ファイル出力を行うプログラムを作成する際には、出力するファイルの文字コードも注意する必要がある。
RandomAccessFileクラス
これまでに紹介した方法は、すべてファイルの新規作成や全文上書きを行う処理となっている。
しかし、実際には「追記」というような処理が必要になることもあるだろう。
そんなときはRandomAccessFileを使用すると良い。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
import java.io.IOException; import java.io.RandomAccessFile; public class Main { public static void main(String[] args) { try { RandomAccessFile raf = new RandomAccessFile("test.txt","rw") ; int count = 1 ; int c = 0 ; while((c = raf.read()) != -1){ if(c == '\n'){ count ++ ; } } String rowData = count + "行目に書き込み\n" ; raf.write(rowData.getBytes()); raf.close(); } catch (IOException ex) { ex.printStackTrace(); } } } |
この例では、「test.txt」を1バイトずつ読み込み、改行コード(「\n」)の数を数え、ファイルの最後に1行ずつ追記する処理を行っている。
RandomAccessFileは、ファイルを読み込み/書き込み両方のモードで開くことができるため、ファイルの書き換えを行うことができる。
また、この例はファイルの最後に追記しているが、途中に加筆をしたり、編集することも可能だ。但し、そのような処理を行うためには、「ファイルポインタ」や「シーク」といったファイル操作の高度な知識とテクニックが必要になるため、ここでの説明は割愛する。
その他のオープンソースライブラリ
Javaの豊富な標準ライブラリに加えて、オープンソースのライブラリを使用することで、様々な形式のファイル出力をサポートする。
例えば、PDFファイルを作成するためのiTextや、Excelファイルを扱うPOI、その他CSVファイルや画像ファイルといった、様々なファイルを作成することができる。
実際にそれらを扱うためには、各ファイル形式の特徴などをある程度理解する必要があるため、もう一歩深い知識が必要になるが、他のプログラム言語に比べて、多くの形式に対応していることは間違いないだろう。
まとめ
Javaのファイル出力について一通りまとめてみたが、参考になっただろうか? 各種クラスについてもお伝えしてきたが、とにかく下記の3ステップを押さえるのが重要だ。
- ファイルを開く
- ファイルの中身を書き込む
- ファイルを閉じる
実践をし、習得いただければと思う。