关于NIO与Socket编程技术指南 “验证 write(ByteBuffer src, long position)方法中的 position 不变性”的不严谨问题

2022-03-29 14:53:40 浏览数 (1)

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方法会有影响底层文件游标位置,但是却不一定影响文件实际写入位置(也是区分追加模式)。

0 人点赞