【问题标题】:Will FileChannel#write always write the whole buffer?FileChannel#write 是否总是写入整个缓冲区?
【发布时间】:2015-07-08 20:30:01
【问题描述】:

(这与Would FileChannel.read read less bytes than specified if there's enough data? 相关(或更确切地说是“相反”)

TL;DR

这是否总是写入整个缓冲区...

ByteBuffer bytes = ...;
fileOutputStream.getChannel().write(bytes);

...或者是否有必要使用这样的循环:

ByteBuffer bytes = ...;
while (bytes.remaining() > 0)
{
    fileOutputStream.getChannel().write(bytes);
}

?


由于comment in another answer,我想问一下,通过调用FileChannel#write(ByteBuffer)Buffer 写入FileChannel 的行为是否有任何保证。


仅供参考:文档说

从给定的缓冲区将字节序列写入此通道。

字节从该通道的当前文件位置开始写入,除非通道处于追加模式,在这种情况下,该位置首先前进到文件末尾。如有必要,文件会增长以容纳写入的字节,然后使用实际写入的字节数更新文件位置。否则,此方法的行为与 WritableByteChannel 接口指定的完全相同。

以及覆盖方法的文档,WritableByteChannel#write(ByteBuffer)

从给定的缓冲区将字节序列写入此通道。

尝试向通道写入最多 r 个字节,其中 r 是在调用此方法时缓冲区中剩余的字节数,即 src.remaining()。

假设写入一个长度为 n 的字节序列,其中 0

除非另有说明,否则写入操作仅在写入所有 r 个请求字节后才会返回。某些类型的通道,取决于它们的状态,可能只写入一些字节,或者根本不写入。例如,处于非阻塞模式的套接字通道不能写入超过套接字输出缓冲区中空闲的字节数。

可以随时调用此方法。但是,如果另一个线程已经对该通道发起了写操作,则对该方法的调用将阻塞,直到第一个操作完成。

参数: src - 要从中检索字节的缓冲区

返回:写入的字节数,可能为零


在上述关于从FileChannel阅读的问题中,在 cmets 中已经对本文档的确切措辞和解释进行了一些讨论。我认为文档中的关键区别在于 read 方法,文档说

读取操作可能不会填满缓冲区,实际上它可能根本不会读取任何字节。

与此相反,write 方法的文档说

除非另有说明,否则写入操作仅在写入所有 r 个请求字节后才会返回。某些类型的通道,取决于它们的状态,可能只写入一些字节,或者根本不写入。

对我来说,这意味着对 FileChannel 的写操作仅在写入所有字节后返回,因为文档中没有另外指定(除了声明返回值可能为 0,但这显然是被覆盖方法的产物)

根据我对最大 80 MB (!) 文件大小的测试,写操作总是 一次写入整个缓冲区。但当然,这只是一个测试,不足以做出深刻的陈述。我试图追踪related OpenJDK classes 中的调用,但这些调用很快就会分化为不同的原生实现——毕竟,这不应该是必要的......

【问题讨论】:

    标签: java filechannel


    【解决方案1】:

    不,不能保证 write() 会耗尽整个缓冲区。该文档确实试图建立实现应该一次性写入所有字节的期望,但它注意不做出任何承诺:

    除非另有说明,写入操作只有在写入所有 r 个请求的字节后才会返回。某些类型的通道,取决于它们的状态[1],可能只写入部分字节或根本不写入。

    FileChannel.write() 同样为不完整的写入留出了空间:

    从给定的缓冲区将字节序列写入此通道。

    字节从该通道的当前文件位置开始写入,除非通道处于追加模式,在这种情况下,该位置首先前进到文件末尾。如有必要,文件会增长以容纳写入的字节,然后用实际写入的字节数更新文件位置。否则,此方法的行为与 WritableByteChannel 接口指定的完全相同。

    因此,虽然文本暗示完整写入是一般情况,不完整写入是例外情况,但它为可能无法(能够)遵守此一般情况的替代/未来实现打开了大门。

    正如您所指出的,这是与 read() 方法的区别。我想这是因为在合并文档时,所有已知和预期的实现都遵循执行完整写入的一般情况。


    [1] 这可能是对非阻塞通道的引用。

    【讨论】:

    • 谢谢,但这基本上是我在问题中已经引用的内容。我认为关键是它说“除非另有说明,否则只有在写入所有 r 个请求的字节后才会返回写入操作。”在一般情况下,对于FileChannel 情况,它确实 not 明确表示它可能会在 写入所有请求的字节之前返回。 (是的,我看到返回值被称为“实际写入的字节数”,但它并没有说这可能小于请求的数字)。有疑问,可能不得不假设它不会写入所有字节
    • @Marco13 我们都引用了文档,答案就在那里。 :) 我强调了至少指出不完整写入可能性的部分。正如你所说,你不能确定,所以你必须考虑到这种可能性。
    猜你喜欢
    • 1970-01-01
    • 2012-09-21
    • 2011-10-10
    • 2012-05-14
    • 1970-01-01
    • 1970-01-01
    • 2011-08-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多