我尝试使用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
有人可以告诉我哪里出错吗?
答案 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.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外部的程序(例如文件资源管理器)可能不会指示此内容。