Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
209 views
in Technique[技术] by (71.8m points)

java - Will FileChannel#write always write the whole buffer?

(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...

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...