NIO與Socket編程技術指南2018.7版中第 2 章通道和 FileChannel 類的使用(第130頁)
關於“驗證 write(ByteBuffer src, long position)方法中的 position 不變性的”不夠嚴謹,首先貼出該書中的示例代碼,file.txt中筆者存了123。
@Test
public void writeAtPos()throws IOException{
FileOutputStream fos = new FileOutputStream("d:/tmp/file.txt");
FileChannel fc = fos.getChannel();
println(fc.position());
fc.position(3);
println(fc.position());
ByteBuffer buffer = ByteBuffer.wrap("hahhahah哈哈".getBytes("utf-8"));
fc.write(buffer,0);
println(fc.position());
}
上面代碼輸出結果如下:
0
3
3
從上面這個例子來看確實如“NIO與Socket編程技術指南”這本書說的一樣,完全沒有問題,接下來看下面這個例子:
@Test
public void writeAtPos2()throws IOException{
FileOutputStream fos = new FileOutputStream("d:/tmp/file.txt",true);
FileChannel fc = fos.getChannel();
println(fc.position());
fc.position(3);
println(fc.position());
ByteBuffer buffer = ByteBuffer.wrap("hahhahah哈哈".getBytes("utf-8"));
fc.write(buffer,0);
println(fc.position());
}
上面代碼輸出結果如下:
6
6
14
之所以說“NIO與Socket編程技術指南”這本書關於這部分的說法不嚴謹,在於FileOutputStream 是否以追加模式創建,將會影響
position()方法返回結果,更準確來說應該是write(ByteBuffer src, long position)方法不影響底層文件遊標位置,但是FileChannel的position返回值卻不一定了!!!
關於FileChannel的position方法可以參考FileChannelImpl的position實現:
public long position() throws IOException {
this.ensureOpen();
synchronized(this.positionLock) {
long var2 = -1L;
int var4 = -1;
long var5;
try {
this.begin();
var4 = this.threads.add();
if (this.isOpen()) {
do {
//要注意的是針對追加模式打開的文件,position返回的是文件的整體大小而不是FileChannel的當前位置!!!!
var2 = this.append ? this.nd.size(this.fd) : this.nd.seek(this.fd, -1L);
} while(var2 == -3L && this.isOpen());
var5 = IOStatus.normalize(var2);
return var5;
}
var5 = 0L;
} finally {
this.threads.remove(var4);
this.end(var2 > -1L);
assert IOStatus.check(var2);
}
return var5;
}
}
PS:
爲了加深這個知識點,建議參考下筆者的另一篇文章:https://blog.csdn.net/john1337/article/details/105114551
position方法會有影響底層文件遊標位置,但是卻不一定影響文件實際寫入位置(也是區分追加模式)。