關於NIO與Socket編程技術指南 “驗證 write(ByteBuffer src, long position)方法中的 position 不變性”的不嚴謹問題

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方法會有影響底層文件遊標位置,但是卻不一定影響文件實際寫入位置(也是區分追加模式)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章