直接字节缓冲区操作文件报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();
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Java NIO(New IO)是在 Java 1.4 中引入的,提供了一种新的 IO API,可以优化 IO 操作的速度和效率。以下是 Java NIO 中用到的一些类和接口: 1. java.nio.Buffer:这是所有缓冲区类的基类,定义了缓冲区的四个属性:容量、位置、限制和标记。 2. java.nio.ByteBuffer:这是字节缓冲区类,用于读写字节数据。 3. java.nio.CharBuffer:这是字符缓冲区类,用于读写字符数据。 4. java.nio.ShortBuffer、java.nio.IntBuffer、java.nio.LongBuffer、java.nio.FloatBuffer、java.nio.DoubleBuffer:这些都是基本类型的缓冲区类,用于读写不同类型的数据。 5. java.nio.channels.Channel:这是通道接口,表示一个可以进行 IO 操作的实体,例如文件或网络连接。 6. java.nio.channels.FileChannel:这是文件通道类,用于对文件进行读写操作。 7. java.nio.channels.SocketChannel:这是网络套接字通道类,用于对 TCP 连接进行读写操作。 8. java.nio.channels.ServerSocketChannel:这是网络服务器套接字通道类,用于监听客户端连接请求。 9. java.nio.channels.Selector:这是选择器类,用于监听多个通道的 IO 事件,避免使用多线程进行 IO 操作。 10. java.nio.charset.Charset:这是字符集类,用于进行字符编码和解码操作。 除了以上提到的类和接口,Java NIO 还有许多其他的类和接口,例如:java.nio.channels.Pipe、java.nio.channels.DatagramChanneljava.nio.channels.AsynchronousChannelGroup、java.nio.channels.AsynchronousServerSocketChanneljava.nio.channels.AsynchronousSocketChannel 等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值