1. 案例说明 NIO 的 Buffer
package com.example.netty.nio; import java.nio.IntBuffer; /** * java.nio.BufferOverflowException */ public class BasicBuffer { public static void main(String[] args) { //举例说明Buffer的使用 //创建一个Buffer,大小为5,即可以存放5个int IntBuffer allocate = IntBuffer.allocate(5); //allocate.put(11); for (int i = 0; i < allocate.capacity(); i++) { allocate.put(i * 2); } //将buffer转换,读写切换 allocate.flip(); while (allocate.hasRemaining()) { System.out.println(allocate.get()); } } }
2. 应用实例 1-本地文件写数据(Channel:通道):
1) 使用前面学习后的 ByteBuffer(缓冲) 和 FileChannel(通道), 将 "hello,尚硅谷" 写入到 file01.txt 中
2) 文件不存在就创建
3) 代码演示
package com.example.netty.nio; import java.io.FileOutputStream; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; public class NIOFileChannel01 { public static void main(String[] args) throws Exception { String str = "Hello Word"; //创建一个输入流 -> channel FileOutputStream fileOutputStream = new FileOutputStream("d://file01.txt"); //通过fileOutputStream 获取对应FileChannel //这个fileChannel真实类型是 FileChannelImpl FileChannel fileChannel = fileOutputStream.getChannel(); //创建一个缓冲区 ByteBuffer ByteBuffer byteBuffer = ByteBuffer.allocate(1024); //将str放入ByteBuffer byteBuffer.put(str.getBytes()); //将ByteBuffer 进行 flip byteBuffer.flip(); //将ByteBuffer 数据写入到FileChannel fileChannel.write(byteBuffer); fileOutputStream.close(); } }
3. 本地文件读数据:
1) 使用前面学习后的 ByteBuffer(缓冲) 和 FileChannel(通道), 将 file01.txt 中的数据读入到程序,并显示在控制台屏幕
2) 假定文件已经存在
3) 代码演示
package com.example.netty.nio; import java.io.File; import java.io.FileInputStream; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; public class NIOFileChannel02 { public static void main(String[] args) throws Exception { File file = new File("d://file01.txt"); //创建文件的输入流 FileInputStream fileInputStream = new FileInputStream(file); //通过fileInputStream 获取对应的fileChannel -> 实际类型 FileChannelImpl FileChannel fileChannel = fileInputStream.getChannel(); //创建缓冲区 ByteBuffer byteBuffer = ByteBuffer.allocate((int)file.length()); //将通道的数据读入到 Buffer fileChannel.read(byteBuffer); //将byteBuffer的字节数据 转成String System.out.println(new String(byteBuffer.array())); fileInputStream.close(); } }
4:使用一个 Buffer 完成文件读取、写入
实例要求:
1) 使用 FileChannel(通道) 和 方法 read , write,完成文件的拷贝
2) 拷贝一个文本文件 1.txt , 放在项目下即可
3) 代码演示
package com.example.netty.nio; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; public class NIOFileChannel03 { public static void main(String[] args) throws Exception { FileInputStream fileInputStream = new FileInputStream(new File("d://file01.txt")); FileChannel fileInputStreamChannel = fileInputStream.getChannel(); FileOutputStream fileOutputStream = new FileOutputStream(new File("d://file02.txt")); FileChannel fileOutputStreamChannel = fileOutputStream.getChannel(); ByteBuffer byteBuffer = ByteBuffer.allocate(512); while (true) { //循环读取 int read = fileInputStreamChannel.read(byteBuffer); System.out.println("read:" + read); if (read == -1) { //表示读完 break; } //将buffer中的数据写入到 fileOutputStreamChannel -- 2.txt byteBuffer.flip(); fileOutputStreamChannel.write(byteBuffer); byteBuffer.clear(); } fileInputStream.close(); fileOutputStream.close(); } }
5:拷贝文件 transferFrom 方法
1) 实例要求:
2) 使用 FileChannel(通道) 和 方法 transferFrom ,完成文件的拷贝
3) 拷贝一张图片
4) 代码演示
package com.example.netty.nio; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.channels.FileChannel; public class NIOFileChannel04 { public static void main(String[] args) throws IOException { //创建相关流 FileInputStream fileInputStream = new FileInputStream("d://1.jpg"); FileOutputStream fileOutputStream = new FileOutputStream("d://2.jpg"); //获取各个流对应的fileChannel FileChannel fileInputStreamChannel = fileInputStream.getChannel(); FileChannel fileOutputStreamChannel = fileOutputStream.getChannel(); //使用transferForm完成拷贝 fileOutputStreamChannel.transferFrom(fileInputStreamChannel, 0 , fileInputStreamChannel.size()); //关闭相关通道和流 fileInputStream.close(); fileOutputStream.close(); } }
6. 关于 Buffer 和 Channel 的注意事项和细节:
1) ByteBuffer 支持类型化的 put 和 get, put 放入的是什么数据类型,get 就应该使用相应的数据类型来取出,否
则可能有 BufferUnderflowException 异常。[举例说明]
package com.example.netty.nio; import java.nio.ByteBuffer; //java.nio.BufferUnderflowException:Buffer内存溢出异常 public class NIOByteBufferPutGet { public static void main(String[] args) { //创建一个Buffer ByteBuffer buffer = ByteBuffer.allocate(64); //类型化方式放入数据 buffer.putInt(100); buffer.putLong(1L); buffer.putShort((short) 4); buffer.putChar('上'); //取出 buffer.flip(); System.out.println(buffer.getInt()); System.out.println(buffer.getLong()); System.out.println(buffer.getShort()); System.out.println(buffer.getChar()); System.out.println(buffer.getChar()); } }
2) 可以将一个普通 Buffer 转成只读 Buffer [举例说明]
package com.example.netty.nio; import java.nio.ByteBuffer; //java.nio.ReadOnlyBufferException:Buffer只读异常 public class ReadOnlyBuffer { public static void main(String[] args) { //创建Buffer ByteBuffer buffer = ByteBuffer.allocate(64); for (int i = 0; i < 64; i++) { buffer.put((byte) i); } //读取 buffer.flip(); //得到一个只读Buffer ByteBuffer readOnlyBuffer = buffer.asReadOnlyBuffer(); System.out.println(readOnlyBuffer.getClass()); //读取 while (readOnlyBuffer.hasRemaining()) { System.out.println(readOnlyBuffer.get()); } readOnlyBuffer.put((byte) 1); //java.nio.ReadOnlyBufferException } }
3) NIO 还提供了 MappedByteBuffer, 可以让文件直接在内存(堆外的内存)中进行修改, 而如何同步到文件,由 NIO 来完成. [举例说明]
package com.example.netty.nio; import java.io.RandomAccessFile; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; /* 说明: 1. MappedByteBuffer 可让文件直接在内存(堆外内存)修改, 操作系统不需要拷贝一次 */ public class MappedByteBufferTest { public static void main(String[] args) throws Exception { RandomAccessFile randomAccessFile = new RandomAccessFile("d://1.txt", "rw"); //获取相应的通道 FileChannel channel = randomAccessFile.getChannel(); /** * 参数 1: FileChannel.MapMode.READ_WRITE 使用的读写模式 * 参数 2: 0 : 可以直接修改的起始位置 * 参数 3: 5: 是映射到内存的大小(不是索引位置) ,即将 1.txt 的多少个字节映射到内存 * 可以直接修改的范围就是 0-5 * 实际类型 DirectByteBuffer */ MappedByteBuffer mappedByteBuffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, 5); mappedByteBuffer.put(0, (byte) 'H'); mappedByteBuffer.put(2, (byte) '9'); mappedByteBuffer.put(5, (byte) '9');//java.lang.IndexOutOfBoundsException:索引越界异常 randomAccessFile.close(); System.out.println("文件修改完成!"); } }
4) 前面我们讲的读写操作,都是通过一个 Buffer 完成的,NIO 还支持 通过多个 Buffer (即 Buffer 数组) 完成读写操作,即 Scattering 和 Gathering 【举例说明】