Java - ファイルに書き込む

Java –ファイルへの書き込み

1. 概要

このチュートリアルでは、write to a file using Javaのさまざまな方法について説明します。 BufferedWriterPrintWriterFileOutputStreamDataOutputStreamRandomAccessFileFileChannel、およびJava 7Filesを使用します。ユーティリティクラス。

また、書き込み中にファイルをロックする方法についても説明し、ファイルへの書き込みに関する最終的なポイントについて説明します。

この記事は、例としてここのthe “Java – Back to Basic” seriesの一部です。

参考文献:

Java –データをファイルに追加

ファイルにデータを追加するための迅速かつ実用的なガイド。

JavaのFileNotFoundException

JavaのFileNotFoundExceptionの迅速で実用的なガイド。

Javaでファイルをコピーする方法

Javaでファイルをコピーする一般的な方法をご覧ください。

2. BufferedWriterで書き込む

簡単に始めましょう–そしてBufferedWriterを使用してStringto a new fileを記述します。

public void whenWriteStringUsingBufferedWritter_thenCorrect()
  throws IOException {
    String str = "Hello";
    BufferedWriter writer = new BufferedWriter(new FileWriter(fileName));
    writer.write(str);

    writer.close();
}

ファイルの出力は次のようになります。

Hello

次に、append a String to the existing fileを実行できます。

@Test
public void whenAppendStringUsingBufferedWritter_thenOldContentShouldExistToo()
  throws IOException {
    String str = "World";
    BufferedWriter writer = new BufferedWriter(new FileWriter(fileName, true));
    writer.append(' ');
    writer.append(str);

    writer.close();
}

ファイルは次のようになります。

Hello World

3. PrintWriterで書き込む

次へ–PrintWriterを使用してフォーマットされたテキストをファイルに書き込む方法を見てみましょう。

@Test
public void givenWritingStringToFile_whenUsingPrintWriter_thenCorrect()
  throws IOException {
    FileWriter fileWriter = new FileWriter(fileName);
    PrintWriter printWriter = new PrintWriter(fileWriter);
    printWriter.print("Some String");
    printWriter.printf("Product name is %s and its price is %d $", "iPhone", 1000);
    printWriter.close();
}

結果のファイルには以下が含まれます。

Some String
Product name is iPhone and its price is 1000$

生の文字列をファイルに書き込むだけでなく、printfメソッドを使用してフォーマットされたテキストも書き込む方法に注意してください。

FileWriterBufferedWriter、さらにはSystem.outを使用してライターを作成できます。

4. FileOutputStreamで書き込む

FileOutputStreamからwrite binary data to a fileを使用する方法を見てみましょう。 次のコードは、String intバイトを変換し、FileOutputStreamを使用してバイトをファイルに書き込みます。

@Test
public void givenWritingStringToFile_whenUsingFileOutputStream_thenCorrect()
  throws IOException {
    String str = "Hello";
    FileOutputStream outputStream = new FileOutputStream(fileName);
    byte[] strToBytes = str.getBytes();
    outputStream.write(strToBytes);

    outputStream.close();
}

もちろん、ファイルの出力は次のようになります。

Hello

5. DataOutputStreamで書き込む

次へ–DataOutputStreamを使用して文字列をファイルに書き込む方法を見てみましょう。

@Test
public void givenWritingToFile_whenUsingDataOutputStream_thenCorrect()
  throws IOException {
    String value = "Hello";
    FileOutputStream fos = new FileOutputStream(fileName);
    DataOutputStream outStream = new DataOutputStream(new BufferedOutputStream(fos));
    outStream.writeUTF(value);
    outStream.close();

    // verify the results
    String result;
    FileInputStream fis = new FileInputStream(fileName);
    DataInputStream reader = new DataInputStream(fis);
    result = reader.readUTF();
    reader.close();

    assertEquals(value, result);
}

6. RandomAccessFileで書き込む

ここで、完全に新しいファイルに書き込んだり、既存のファイルに追加したりするのではなく、既存のファイル内で書き込みと編集を行う方法を説明しましょう。 簡単に言えば、ランダムアクセスが必要です。

RandomAccessFileを使用すると、ファイルの先頭からのオフセットをバイト単位で指定して、ファイル内の特定の位置に書き込むことができます。 次のコードは、ファイルの先頭からオフセットを指定して整数値を書き込みます。

private void writeToPosition(String filename, int data, long position)
  throws IOException {
    RandomAccessFile writer = new RandomAccessFile(filename, "rw");
    writer.seek(position);
    writer.writeInt(data);
    writer.close();
}

特定の場所に保存されているintを読み取りたい場合は、次の方法を使用できます。

private int readFromPosition(String filename, long position)
  throws IOException {
    int result = 0;
    RandomAccessFile reader = new RandomAccessFile(filename, "r");
    reader.seek(position);
    result = reader.readInt();
    reader.close();
    return result;
}

関数をテストするために、整数を記述して編集し、最後に読み返します。

@Test
public void whenWritingToSpecificPositionInFile_thenCorrect()
  throws IOException {
    int data1 = 2014;
    int data2 = 1500;

    writeToPosition(fileName, data1, 4);
    assertEquals(data1, readFromPosition(fileName, 4));

    writeToPosition(fileName2, data2, 4);
    assertEquals(data2, readFromPosition(fileName, 4));
}

7. FileChannelで書き込む

大きなファイルを処理している場合、FileChannelは標準IOよりも高速になる可能性があります。 次のコードは、FileChannelを使用してStringをファイルに書き込みます。

@Test
public void givenWritingToFile_whenUsingFileChannel_thenCorrect()
  throws IOException {
    RandomAccessFile stream = new RandomAccessFile(fileName, "rw");
    FileChannel channel = stream.getChannel();
    String value = "Hello";
    byte[] strBytes = value.getBytes();
    ByteBuffer buffer = ByteBuffer.allocate(strBytes.length);
    buffer.put(strBytes);
    buffer.flip();
    channel.write(buffer);
    stream.close();
    channel.close();

    // verify
    RandomAccessFile reader = new RandomAccessFile(fileName, "r");
    assertEquals(value, reader.readLine());
    reader.close();
}

8. Filesクラスで書き込む

Java 7では、新しいユーティリティクラスFilesとともに、ファイルシステムを操作する新しい方法が導入されています。 Filesクラスを使用して、ファイルとディレクトリを作成、移動、コピー、削除することもできます。また、ファイルの読み取りと書き込みにも使用できます。

@Test
public void givenUsingJava7_whenWritingToFile_thenCorrect()
  throws IOException {
    String str = "Hello";

    Path path = Paths.get(fileName);
    byte[] strToBytes = str.getBytes();

    Files.write(path, strToBytes);

    String read = Files.readAllLines(path).get(0);
    assertEquals(str, read);
}

9. 一時ファイルに書き込む

それでは、一時ファイルに書き込んでみましょう。 次のコードは、一時ファイルを作成し、それに文字列を書き込みます。

@Test
public void whenWriteToTmpFile_thenCorrect() throws IOException {
    String toWrite = "Hello";
    File tmpFile = File.createTempFile("test", ".tmp");
    FileWriter writer = new FileWriter(tmpFile);
    writer.write(toWrite);
    writer.close();

    BufferedReader reader = new BufferedReader(new FileReader(tmpFile));
    assertEquals(toWrite, reader.readLine());
    reader.close();
}

ご覧のとおり、興味深いのは一時ファイルの作成だけです。それ以降は、ファイルへの書き込みは同じです。

10. 書き込む前にファイルをロックする

最後に、ファイルへの書き込み時に、他のユーザーが同時にそのファイルに書き込みを行っていないことを確認する必要がある場合があります。 基本的に-書き込み中にそのファイルをロックできる必要があります。

FileChannelを使用して、ファイルに書き込む前にファイルをロックしてみましょう。

@Test
public void whenTryToLockFile_thenItShouldBeLocked()
  throws IOException {
    RandomAccessFile stream = new RandomAccessFile(fileName, "rw");
    FileChannel channel = stream.getChannel();

    FileLock lock = null;
    try {
        lock = channel.tryLock();
    } catch (final OverlappingFileLockException e) {
        stream.close();
        channel.close();
    }
    stream.writeChars("test lock");
    lock.release();

    stream.close();
    channel.close();
}

ロックを取得しようとしたときにファイルがすでにロックされている場合は、OverlappingFileLockExceptionがスローされることに注意してください。

11. ノート

ファイルへの書き込み方法を数多く検討した後、いくつかの重要な注意事項について説明しましょう。

  • 存在しないファイルから読み取ろうとすると、FileNotFoundExceptionがスローされます

  • 存在しないファイルに書き込もうとすると、ファイルが最初に作成され、例外はスローされません。

  • 暗黙的に閉じられていないため、使用後にストリームを閉じることは、それに関連付けられているリソースを解放するために非常に重要です。

  • 出力ストリームでは、close()メソッドはリソースを解放する前にflush()を呼び出します。これにより、バッファリングされたバイトがストリームに強制的に書き込まれます。

一般的な使用方法を見ると、たとえば、PrintWriterがフォーマットされたテキストの書き込みに使用されていることがわかります。バイナリデータを書き込むFileOutputStream;プリミティブデータ型を書き込むためのDataOutputStreamRandomAccessFileは特定の位置に書き込みます。 FileChannelを使用すると、大きなファイルにすばやく書き込むことができます。 これらのクラスのAPIの中には、さらに多くのAPIを許可するものもありますが、ここから始めるのがよいでしょう。

12. 結論

この記事では、Javaを使用してファイルにデータを書き込む多くのオプションを説明します。

これらすべての例とコードスニペットcan be found over on GitHub projectの実装–これはMavenベースのプロジェクトであるため、そのままインポートして実行するのは簡単です。