一、在学习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(); }