直接字節緩衝區操作文件報java.nio.channels.NonWritableChannelException解決過程

一、在學習nio相關api的時候,通過FileChannel.map方法獲取直接字節緩衝區的時候報了一個NonWritableChannelException的異常
測試代碼如下:

public static void testMappedByteBuffer() throws IOException {
        // 這裏不能通過文件輸出流去獲取通道,因爲獲取到的通道是隻讀的
        FileInputStream fileInputStream = new FileInputStream("D:\\text.txt");
        FileChannel channel = fileInputStream.getChannel();

        MappedByteBuffer map = channel.map(FileChannel.MapMode.READ_WRITE, 0, 5);
        map.put((byte)'A');
        fileInputStream.close();
        channel.close();
    }

異常信息如下

Exception in thread "main" java.nio.channels.NonWritableChannelException
	at sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:874)
	at com.joe.TestBuffer.testMappedByteBuffer(TestBuffer.java:138)
	at com.joe.TestBuffer.main(TestBuffer.java:15)

報錯位置是在FileChannelImpl.java:874,點進去看下
在這裏插入圖片描述
代碼邏輯大概意思是,通過FileChannelImpl.map獲取直接字節緩衝區的時候,會判斷你傳入的MapMode是不是非只讀(READ_ONLY),如果是非只讀,他會判斷writable這個變量是否爲true,而writable是FileChannelImpl實例化的時候傳進來的
在這裏插入圖片描述
而我這裏的管道獲取是通過文件輸入流(FileInputStream)的getChannel方法,所以去看下這個方法的代碼,如下
在這裏插入圖片描述
通過這裏可以看到,getChannel調用的是FileChannelImpl的open(),這個open其實也是會調用FileChannelImpl的構造去創建FileChannelImpl,這裏傳進去的第四個參數爲false,所以通過FileInputStream.getChannel()獲取的是一個只讀的管道,所以剛纔那個writable爲false,所以會拋出NonWritableChannelException異常。
二、解決方法
①將MappedByteBuffer map = channel.map(FileChannel.MapMode.READ_WRITE, 0, 5);中的MapMode.READ_WRITE改爲MapMode.READ_ONLY,但是這樣就沒有意義了,因爲我是想通過直接字節緩衝區去修改文件,這樣改爲只讀,那麼並不能進行修改
②改用RandomAccessFile獲取管道,因爲RandomAccessFile支持讀取和寫入隨機訪問文件
在這裏插入圖片描述
他的getChannel方法創建的是即支持讀又支持寫的Channel
在這裏插入圖片描述
三、最終的代碼

    public static void testMappedByteBuffer() throws IOException {
        // 這裏不能通過文件輸出流去獲取通道,因爲獲取到的通道是隻讀的
        /*FileInputStream fileInputStream = new FileInputStream("D:\\text.txt");
        FileChannel channel = fileInputStream.getChannel();*/

        // 這裏的"rw"是指支持讀和寫
        RandomAccessFile randomAccessFile = new RandomAccessFile("D:\\text.txt","rw");
        FileChannel channel = randomAccessFile.getChannel();

        MappedByteBuffer map = channel.map(FileChannel.MapMode.READ_WRITE, 0, 5);
        map.put((byte)'A');
        randomAccessFile.close();
        channel.close();
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章