直接字节缓冲区操作文件报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();
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章