2

FileChannelを使用して、ファイルの特定の位置に特定のバイトを書き込もうとしました。しかし実際には、ファイルは変更を書き込む最後の位置に縮小されます。私はこのようにします:

    Path path = Paths.get("I://music - Copy.mp3");

    System.out.println(Files.size(path)/1024 + "KB");

    try (FileChannel chan = new FileOutputStream(path.toFile()).getChannel()) {
        chan.position(1024 * 1024);

        ByteBuffer b = ByteBuffer.allocate(1024);
        chan.write(b);

        System.out.println("Write 1KB of data");
    }

    System.out.println(Files.size(path)/1024 + "KB");

これが私が得た出力です:

3670KB
Write 1KB of data
1025KB

どこが悪いのか誰か教えてもらえますか?

4

3 に答える 3

4

ファイルに追加できるFileOutputStreamコンストラクターがありません。上記のように作成すると、ファイルの内容が上書きされます。

于 2012-05-17T10:23:39.027 に答える
1

追加モードでを使用し、FileOutputStream現在のチャネル位置を指定しないようにしてください。

new FileOutputStream(path.toFile(), true)

upd。前の答えを見ませんでした

于 2012-05-17T10:28:38.403 に答える
1

FileOutputStreamは、追加モードでない場合、ファイルをゼロの長さに切り捨てます。ファイルの内容を破棄して最初からやり直すほど、ファイルの内容を上書きすることはありません。chan.size()これは、チャネルの作成後に呼び出すことで確認できます。これにより、0が得られます。[1]

FileChannelは、ファイルの終わりを超えて進め、そこに書き込むように指示することができます。これにより、ファイルサイズが位置+ bytes_writtenに増加します(私の強調):

現在のサイズよりも大きい値に位置を設定することは合法ですが、エンティティのサイズは変更されません。[..]後でそのような位置にバイトを書き込もうとすると、エンティティは新しいバイトに対応するように成長します。前のファイルの終わりと新しく書き込まれたバイトの間のバイトの値は指定されていません。

したがって、FileChannelが書き込み後にファイルを切断しているように見えますが、FileOutputStreamは0の長さに切り捨てられ、FileChannelはそれを再び展開します。

これを防ぐには、FileOutputStreamを使用してチャネルを作成しないでください。パスがあるので、電話Files.newByteChannelまたはFileChannel.open

Path path = Paths.get("I://music - Copy.mp3");

System.out.println(Files.size(path)/1024 + "KB");

// pick either:
try (FileChannel chan = FileChannel.open(path, StandardOpenOption.WRITE)) {
try (SeekableByteChannel chan = Files.newByteChannel(path, StandardOpenOption.WRITE)) {
    chan.position(1024 * 1024);

    ByteBuffer b = ByteBuffer.allocate(1024);
    chan.write(b);

    System.out.println("Write 1KB of data");
}

System.out.println(Files.size(path)/1024 + "KB");

[1]ファイルエクスプローラーなど、JVMの外部にあるプログラムは、ストリームをフラッシュまたは閉じるまで、これを示さない場合があることに注意してください。

于 2015-06-27T17:11:43.833 に答える