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)

更新。没看到前面的答案

于 2012-05-17T10:28:38.403 回答
1

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

FileChannels 可以前进到文件末尾并被告知在那里写入;这会导致文件大小增加到 position + 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 之外的程序(例如文件资源管理器)可能不会指示这一点。

于 2015-06-27T17:11:43.833 回答