当前位置: 首页 > 知识库问答 >
问题:

FileChannel#write是否总是写入整个缓冲区?

华俊弼
2023-03-14

(这与(或者相反)如果有足够的数据,FileChannel.read读取的字节会比指定的少吗?)

TL;博士:

这会一直写入整个缓冲区吗。。。

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

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

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

?

由于另一个答案中的评论,我想问一下,通过调用FileChannel#write(ByteBuffer)FileChannel写入缓冲区的行为是否有任何保证。

仅供参考:文件上说

从给定缓冲区向该通道写入字节序列。

除非通道处于追加模式,否则从该通道的当前文件位置开始写入字节,在这种情况下,该位置首先前进到文件的末尾。如有必要,文件将被扩展以容纳写入的字节,然后文件位置将根据实际写入的字节数进行更新。否则,此方法将完全按照WritableByteChannel接口指定的方式运行。

和重写方法的留档,WritableByteChannel#写(ByteBuffer)

从给定缓冲区向该通道写入字节序列。

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

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

除非另有规定,否则写入操作仅在写入所有r请求的字节后返回。某些类型的通道,根据其状态,可能只写入部分字节,也可能根本不写入。例如,非阻塞模式下的套接字通道写入的字节数不能超过套接字输出缓冲区中的可用字节数。

可以随时调用此方法。但是,如果另一个线程已经在这个通道上启动了写操作,那么这个方法的调用将被阻止,直到第一个操作完成。

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

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

在上面提到的关于从FileChannel读取的问题中,在评论中已经讨论了这个留档的确切措辞和解释。我认为留档的关键区别在于,对于读取方法,留档说

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

与此相反,write方法的文档显示

除非另有规定,否则写入操作仅在写入所有r请求的字节后返回。某些类型的通道,根据其状态,可能只写入部分字节,也可能根本不写入。

对我来说,这意味着FileChannel上的写入操作只会在写入所有字节后返回,因为文档中没有另外指定它(除了返回值可能为0的语句,但这显然是重写方法的产物)

根据我的测试,文件大小高达80MB(!),写入操作总是一次写入整个缓冲区。但当然,这只是一个测试,不足以做出深刻的陈述。我试图跟踪相关OpenJDK类中的调用,但这些调用很快就会分化为不同的本机实现——毕竟,这应该不是必需的。。。


共有1个答案

太叔睿
2023-03-14

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

除非另有规定,否则写入操作仅在写入所有r请求的字节后返回。某些类型的通道,取决于它们的状态[1],可能只写入部分字节,也可能根本不写入。

文件频道。write()同样为不完整的写入留出了空间:

从给定缓冲区向该通道写入字节序列。

除非通道处于追加模式,否则从该通道的当前文件位置开始写入字节,在这种情况下,该位置首先前进到文件的末尾。如有必要,文件将被扩展以容纳写入的字节,然后文件位置将根据实际写入的字节数进行更新。否则,此方法将完全按照WritableByteChannel接口指定的方式运行。

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

正如您指出的,这是与read()方法不同的地方。我想这是因为,在合并留档时,所有已知和预期的实现都坚持执行完全写入的一般情况。

[1] 这可能是指非阻塞通道。

 类似资料:
  • 问题内容: 是缓冲还是无缓冲? 我读到这是的对象,并且是所引用的对象的类型。 而且它们都是Unbuffered的,所以为什么要刷新unbuffered …是否可以刷新unbuffered,我已经读过它们被立即写入。 问题答案: 是“标准”输出。在大多数操作系统上,终端io被缓冲,并且支持分页。 在Javadoc中, “标准”输出流。该流已经打开并且准备接受输出数据。通常,此流对应于主机环境或用户指

  • 今天早些时候很无聊,我开始思考Java中缓冲和非缓冲字节流的相对性能。作为一个简单的测试,我下载了一个相当大的文本文件,并编写了一个简短的程序来确定缓冲流在复制文件时的效果。进行了四项测试: 使用无缓冲的输入和输出字节流复制文件 毫不奇怪,使用缓冲输入和输出流比使用无缓冲流快几个数量级。然而,真正有趣的事情(至少对我来说)是案例2和案例3之间的速度差异。部分样本结果如下: 对于那些感兴趣的人,可以

  • 问题内容: 我想做的是在缓冲区上绘制图形,然后将其原样复制到画布上,这样我就可以制作动画并避免闪烁。但是我找不到这个选项。有人知道我该怎么做吗? 问题答案: 下面的有用链接除了显示使用双缓冲的示例和优点之外,还显示了使用html5 canvas元素的其他一些性能提示。它包含指向jsPerf测试的链接,这些链接将跨浏览器的测试结果汇总到Browserscope数据库中。这样可以确保性能提示得到验证。

  • 我有两个问题关于StreamingOutput在泽西: 1) 它已经被jax-rs运行时缓冲了吗?我见过一些例子,在重写write()方法时,从OutputStream对象创建BufferedWriter。但我想知道这是否真的有必要。 2) Jersey或jax rs运行时是否在流完成后关闭OutputStream对象? 谢谢 格格

  • 问题内容: 我正在使用低级I / O函数“写入”以我的代码(Linux上的C语言)将一些数据写入磁盘。首先,我将数据存储在内存缓冲区中,然后在缓冲区已满时使用“写入”将数据写入磁盘。那么“写”的最佳缓冲区大小是多少?根据我的测试,更快不是越大,所以我在这里寻找答案。 问题答案: 进行写操作可能是文件系统块大小的倍数,因此可能会有一些优势,尤其是在就地更新文件的情况下。如果向文件中写入的块少于部分块

  • 我试图读取名为使用。JS代码: 但是运行代码会产生这个错误: 这个错误对我来说毫无意义。由返回的缓冲区怎么可能不是的实例?将替换为或也不能解决此问题。我目前正在使用节点。JS版本14.17.6(LTS)。