Buffer 和 Channel使用注意
-
ByteBuffer 支持类型化的put 和 get, put 放入的是什么数据类型,get就应该使用相应的数据类型来取出,否则可能有 BufferUnderflowException 异常。
-
代码案例
public class NIOByteBufferPutGet { public static void main(String[] args) { //创建一个Buffer ByteBuffer buffer = ByteBuffer.allocate(64); //类型化方式放入数据 buffer.putInt(100); buffer.putLong(9); buffer.putChar('尚'); buffer.putShort((short) 4); //取出 buffer.flip(); // 取数据时,需要使用对应的数据类型,否则会报错 System.out.println(buffer.getInt()); System.out.println(buffer.getLong()); System.out.println(buffer.getChar()); System.out.println(buffer.getShort()); } }
-
可以将一个普通Buffer 转成只读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()); } // 由于是只读,所以写时会抛出异常ReadOnlyBufferException readOnlyBuffer.put((byte)100); } }
-
NIO 还提供了 MappedByteBuffer, 可以让文件直接在内存(堆外的内存)中进行修改, 而如何同步到文件由NIO 来完成
-
代码案例
import java.io.RandomAccessFile; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; /* * MappedByteBuffer 可让文件直接在内存(堆外内存)修改, 操作系统不需要拷贝一次 */ public class MappedByteBufferTest { public static void main(String[] args) throws Exception { RandomAccessFile randomAccessFile = new RandomAccessFile("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(3, (byte) '9'); mappedByteBuffer.put(5, (byte) 'Y'); // 在索引为5的位置修改时,会抛出异常IndexOutOfBoundsException randomAccessFile.close(); System.out.println("修改成功~~"); } }
-
NIO 还支持 通过多个Buffer (即 Buffer 数组) 完成读写操作,即 Scattering 和 Gathering
-
代码案例
import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.Arrays; /** * Scattering:将数据写入到buffer时,可以采用buffer数组,依次写入 [分散] * Gathering: 从buffer读取数据时,可以采用buffer数组,依次读 */ public class ScatteringAndGatheringTest { public static void main(String[] args) throws Exception { //使用 ServerSocketChannel 和 SocketChannel 网络 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); InetSocketAddress inetSocketAddress = new InetSocketAddress(7000); //绑定端口到socket ,并启动 serverSocketChannel.socket().bind(inetSocketAddress); //创建buffer数组 ByteBuffer[] byteBuffers = new ByteBuffer[2]; byteBuffers[0] = ByteBuffer.allocate(5); byteBuffers[1] = ByteBuffer.allocate(3); //等客户端连接(telnet) SocketChannel socketChannel = serverSocketChannel.accept(); int messageLength = 8; //假定从客户端接收8个字节 //循环的读取 while (true) { int byteRead = 0; while (byteRead < messageLength ) { long l = socketChannel.read(byteBuffers); byteRead += l; //累计读取的字节数 System.out.println("byteRead=" + byteRead); //使用流打印, 看看当前的这个buffer的position 和 limit Arrays.asList(byteBuffers).stream().map(buffer -> "postion=" + buffer.position() + ", limit=" + buffer.limit()).forEach(System.out::println); } //将所有的buffer进行flip Arrays.asList(byteBuffers).forEach(buffer -> buffer.flip()); //将数据读出显示到客户端 long byteWirte = 0; while (byteWirte < messageLength) { long l = socketChannel.write(byteBuffers); // byteWirte += l; } //将所有的buffer 进行clear Arrays.asList(byteBuffers).forEach(buffer-> { buffer.clear(); }); System.out.println("byteRead:=" + byteRead + " byteWrite=" + byteWirte + ", messagelength" + messageLength); } } }
- 启动测试
# 运行main方法 # 打开cmd telnet 127.0.0.1 7000 # 按住ctrl + ] # 发送消息6个字节 send helloa # 控制台打印 byteRead=6 postion=5, limit=5 postion=1, limit=3 # 重新连接,发送8个字节 send helloabc # 控制台打印 byteRead=8 postion=5, limit=5 postion=3, limit=3 byteRead:=8 byteWrite=8, messagelength8
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决