Will FileChannel#write always write the whole buffer?
Asked Answered
T

1

18

(This is related to (or rather the "opposite" of) Would FileChannel.read read less bytes than specified if there's enough data? )

TL;DR :

Will this always write the whole buffer...

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

...or is it necessary to use a loop like this:

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

?


Due to a comment in another answer, I'd like to ask whether there are any guarantees regarding the behavior of writing a Buffer to a FileChannel by calling FileChannel#write(ByteBuffer).


Just for reference: The documentation says

Writes a sequence of bytes to this channel from the given buffer.

Bytes are written starting at this channel's current file position unless the channel is in append mode, in which case the position is first advanced to the end of the file. The file is grown, if necessary, to accommodate the written bytes, and then the file position is updated with the number of bytes actually written. Otherwise this method behaves exactly as specified by the WritableByteChannel interface.

and the documentation of the overridden method, WritableByteChannel#write(ByteBuffer) says

Writes a sequence of bytes to this channel from the given buffer.

An attempt is made to write up to r bytes to the channel, where r is the number of bytes remaining in the buffer, that is, src.remaining(), at the moment this method is invoked.

Suppose that a byte sequence of length n is written, where 0 <= n <= r. This byte sequence will be transferred from the buffer starting at index p, where p is the buffer's position at the moment this method is invoked; the index of the last byte written will be p + n - 1. Upon return the buffer's position will be equal to p + n; its limit will not have changed.

Unless otherwise specified, a write operation will return only after writing all of the r requested bytes. Some types of channels, depending upon their state, may write only some of the bytes or possibly none at all. A socket channel in non-blocking mode, for example, cannot write any more bytes than are free in the socket's output buffer.

This method may be invoked at any time. If another thread has already initiated a write operation upon this channel, however, then an invocation of this method will block until the first operation is complete.

Parameters: src - The buffer from which bytes are to be retrieved

Returns: The number of bytes written, possibly zero


In the above mentioned question about reading from a FileChannel, there has been some discussion in the comments about the exact wording and interpretation of this documentation. I think the crucial difference in the documentation is that for the read method, the documentation says

A read operation might not fill the buffer, and in fact it might not read any bytes at all.

In contrast to that, the documentation of the write method says

Unless otherwise specified, a write operation will return only after writing all of the r requested bytes. Some types of channels, depending upon their state, may write only some of the bytes or possibly none at all.

For me, this means that the write operation on a FileChannel will only return after all bytes have been written, because it is not specified otherwise in the documentation (except for the statement that the return value may be 0, but this is obviously an artifact from the overridden method)

From my tests with file sizes of up to 80 MB (!), the write operation always wrote the whole buffer at once. But of course, this was just a test, and is not sufficient for a profound statement. I tried to trace the calls in the related OpenJDK classes, but these quickly diverge into different native implementations - and after all, this should not be necessary...

Teeny answered 29/4, 2015 at 13:47 Comment(0)
A
2

No, there are no guarantees that write() will exhaust the whole buffer. The documentation does try to establish the expectation that implementations should write all bytes in one go, but it takes care to make no promises:

Unless otherwise specified, a write operation will return only after writing all of the r requested bytes. Some types of channels, depending upon their state[1], may write only some of the bytes or possibly none at all.

FileChannel.write() similarly leaves room for incomplete writes:

Writes a sequence of bytes to this channel from the given buffer.

Bytes are written starting at this channel's current file position unless the channel is in append mode, in which case the position is first advanced to the end of the file. The file is grown, if necessary, to accommodate the written bytes, and then the file position is updated with the number of bytes actually written. Otherwise this method behaves exactly as specified by the WritableByteChannel interface.

So, while the text implies the full write to be the general case and incomplete writes to be the exception, it leaves the door open for alternative/future implementations that may not (be able to) adhere to this general case.

As you point out, this is a difference in approach from read(). I imagine this is because, at the time of consolidating the documentation, all known and intended implementations adhered to this general case of performing complete writes.


[1] This is probably a reference to non-blocking channels.

Adjustment answered 28/6, 2015 at 16:2 Comment(2)
Thanks, but this is basically what I already quoted in the question. I think the crucial point is that it says "Unless otherwise specified, a write operation will return only after writing all of the r requested bytes." in the general case, and for the FileChannel case, it does not say explicitly that it may return before writing all the requested bytes. (Yes, I see that the return value is referred to as "the number of bytes actually written", but it does not say that this may be less than the requested number). In doubt, one probably has to assume that it will not write all bytesTeeny
@Teeny We both quoted the documentation, and the answer is in there. :) I emphasised the parts that point to at least the possibility of incomplete writes. As you say, you can't be sure, so you have to take that possibility into account.Adjustment

© 2022 - 2024 — McMap. All rights reserved.