Java:使用FileChannel写入文件会使文件缩小吗?

时间:2012-05-17 10:18:32

标签: java file-io filechannel

我尝试使用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

有人可以告诉我哪里出错吗?

3 个答案:

答案 0 :(得分:4)

您错过了允许附加到文件的FileOutputStream constructor。如果您按上述方法创建它,则会覆盖该文件的内容。

答案 1 :(得分:1)

尝试在附加模式下使用FileOutputStream并避免指定当前频道位置:

new FileOutputStream(path.toFile(), true)

UPD。没有看到以前的答案

答案 2 :(得分:1)

FileOutputStream在不处于追加模式时将文件截断为零长度。它不会覆盖文件的内容,因为它会丢弃内容并重新开始。您可以在创建通道后调用chan.size()来验证这一点,这将为您提供0. [1]

FileChannels可以超过文件末尾并告诉写入;这会导致文件大小增加到位置+ bytes_written(强调我的):

  

将位置设置为大于当前大小的值是合法的,但不会更改实体的大小。 [..] 稍后尝试在这样的位置写入字节将导致实体增长以容纳新字节;未指定前一个文件结尾和新写入字节之间的任何字节值。

因此,虽然看起来FileChannel在写入后切断了文件,但FileOutputStream会截断为0长度,然后FileChannel再次展开它。

要防止这种情况发生,请避免使用FileOutputStream来创建频道。您有一个路径,因此您可以拨打Files.newByteChannelFileChannel.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外部的程序(例如文件资源管理器)可能不会指示此内容。