web-dev-qa-db-ja.com

NIOを使用してInputStreamをファイルに書き込む方法は?

私はInputStreamFileに書き込むために次の方法を使用しています:

private void writeToFile(InputStream stream) throws IOException {
    String filePath = "C:\\Test.jpg";
    FileChannel outChannel = new FileOutputStream(filePath).getChannel();       
    ReadableByteChannel inChannel = Channels.newChannel(stream);
    ByteBuffer buffer = ByteBuffer.allocate(1024);

    while(true) {
        if(inChannel.read(buffer) == -1) {
            break;
        }

        buffer.flip();
        outChannel.write(buffer);
        buffer.clear();
    }

    inChannel.close();
    outChannel.close();
}

これがNIOを使用する正しい方法かどうか疑問に思っていました。メソッドを読みました FileChannel.transferFrom 、これは3つのパラメータを取ります:

  1. ReadableByteChannel src
  2. ロングポジション
  3. ロングカウント

私の場合、srcしかなく、positioncountがありません。この方法を使用してファイルを作成する方法はありますか?

また、画像については、InputStreamとNIOからのみ画像を作成するより良い方法はありますか?

どんな情報も私にとって非常に役に立ちます。ここにも同様の質問がありますが、私の場合に適した特定の解決策は見つかりません。

17
Tapas Bose

いいえ、それは正しくありません。データを失うリスクがあります。正規のNIOコピーループは次のとおりです。

_while (in.read(buffer) >= 0 || buffer.position() > 0)
{
  buffer.flip();
  out.write(buffer);
  buffer.compact();
}
_

EOSでの出力のフラッシュを処理する変更されたループ条件と、短い書き込みの可能性を処理するcompact()ではなくclear(),の使用に注意してください。

同様に、正規のtransferTo()/transferFrom()ループは次のとおりです。

_long offset = 0;
long quantum = 1024*1024; // or however much you want to transfer at a time
long count;
while ((count = out.transferFrom(in, offset, quantum)) > 0)
{
    offset += count;
}
_

クォンタム全体の転送は保証されていないため、ループで呼び出す必要があります。

7
user207421

Files.copyを使用します

Files.copy(is, Paths.get(filePath));

あなたのバージョンについては

  1. ByteBuffer.allocateDirectはより高速です-JavaはネイティブI/O操作を直接実行するために最善を尽くします。

  2. クローズは信頼性が低く、最初に失敗した場合、2番目は実行されません。代わりにtry-with-resourcesを使用してください。チャネルもAutoCloseableです。

46