NIO与Socket编程技术指南2018.7版中第 2 章通道和 FileChannel 类的使用(第130页)
关于“验证 write(ByteBuffer src, long position)方法中的 position 不变性的”不够严谨,首先贴出该书中的示例代码,file.txt中笔者存了123。
代码语言:javascript复制@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());
}
上面代码输出结果如下:
代码语言:javascript复制0
3
3
从上面这个例子来看确实如“NIO与Socket编程技术指南”这本书说的一样,完全没有问题,接下来看下面这个例子:
代码语言:javascript复制 @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());
}
上面代码输出结果如下:
代码语言:javascript复制6
6
14
之所以说“NIO与Socket编程技术指南”这本书关于这部分的说法不严谨,在于FileOutputStream 是否以追加模式创建,将会影响
position()方法返回结果,更准确来说应该是write(ByteBuffer src, long position)方法不影响底层文件游标位置,但是FileChannel的position返回值却不一定了!!!
关于FileChannel的position方法可以参考FileChannelImpl的position实现:
代码语言:javascript复制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方法会有影响底层文件游标位置,但是却不一定影响文件实际写入位置(也是区分追加模式)。