用来处理Channel中数据的一种数据结构, 与Channel一致都是双向的, 可读可写
因为数据都是用字节的方式传播, 使用最多的是ByteBuffer
// 通过allocate创建一个 长度为5的buffer, 意为可以存放5个int
IntBuffer buffer = IntBuffer.allocate(5);
IntBuffer buffer = IntBuffer.allocate(5);
for (int i = 0; i < 5; i++) {
// 存放数据,如果使用put(int i)方法, 那么buffer指针会自动+1
// 每次存放数据不用选定下标位置
buffer.put(i);
}
// 如果使用put(int index,int i)规定了数据存放的下标, 那么buffer指针不会自动+1
buffer.put(i, j);
// 通过数组存放数据
buffer.put(intArray);
for (int i = 0; i < 5; i++) {
// 存放数据,如果使用get()方法, 那么buffer指针会自动+1
// 每次存放数据不用选定下标位置
buffer.get(i);
// 如果使用下标获取数据, 怎么指针不会变化
}
ByteBuffer byteBf = ByteBuffer.allocate(5);
byteBf.putInt(1);
byteBf.putLong(2L);
byteBf.putShort((short) 3);
byteBf.putDouble(4D);
// 如果需要get也要安装对饮顺序get, 否则会出现BufferUnderflowException异常
byteBf.flip();
int anInt = byteBf.getInt();
long aLong = byteBf.getLong();
short aShort = byteBf.getShort();
double aDouble = byteBf.getDouble();
// 将我们的byteBuffer转换成readOnlyBuffer(只读buffer), 只允许get, 不允许put
ByteBuffer readOnlyBuffer = buffer.asReadOnlyBuffer();
/**
* 创建一个RandomAccessFile对象
* RandomAccessFile支持"随机访问"的方式, 不同于流需要一个一个的执行
* 可以直接跳转到文件的任意位置进行修改
* 这里通过RandomAccessFile直接获取Channel对象
*/
RandomAccessFile file = new RandomAccessFile("1.txt", "rw");
FileChannel channel = file.getChannel();
/**
* 参数1: 使用什么模式, 读写
* 参数2: 可以修改的起始位置
* 参数3: 映射到虚拟内存的大小
* 这里是读写模式创建buffer,起始位置为0, 大小为5, 一共可修改5个字节
*/
MappedByteBuffer map = channel.map(FileChannel.MapMode.READ_WRITE, 0, 5);
map.put(0, (byte) 'L');
map.put(1, (byte) 'X');
// index不可为5, 大小设置为5, index最大值为4, 否则会出现越界异常
map.put(4, (byte) 'C');
// 创建一个ByteBuffer数组, 并初始化大小为5
ByteBuffer[] buffers = new ByteBuffer[2];
Arrays.stream(buffers).forEach(buffer -> buffer = ByteBuffer.allocate(5));
// 将channel中的数据读取到buffer数组中(分散)
channel.read(buffers);
// 将buffer数组中的数据写入到channel中(聚合)
// 注: 先反转buffer
Arrays.stream(buffers).forEach(ByteBuffer::flip);
channel.write(buffers);

buffer的创建,读,写,flip操作对4个属性的修改

channel可以看做是一个socket连接, 可以看做是一个流, 与流不同的是channel是双向的
/**
* FileChannel.open(Path path, OpenOption... options)
* 参数1: Path对象, 定义一个文件地址信息
* 参数2: 可变参数, 指定文件读写模式, 常用StandardOpenOption指定
* 这里指定读写模式
*/
FileChannel channel = FileChannel.open(Paths.get("D://1.txt"), StandardOpenOption.READ, StandardOpenOption.WRITE);
/**
* 通过流对象获取的Channel只有读或者写的模式
* - 输入流只有读模式
* - 输出流只有写模式
* - 注意: 写模式会出现替换和追加的方式,
* 可在流对象的第二个参数boolean append指定(true/false)
*/
// 通过输入流创建Channel
FileInputStream in = new FileInputStream("D://1.txt");
FileChannel inChannel = in.getChannel();
// 通过输出流创建Channel
FileOutputStream out = new FileOutputStream("D://1.txt");
FileChannel outChannel = out.getChannel();
// 通过输入流创建Channel
FileInputStream in = new FileInputStream("D://1.txt");
FileChannel inChannel = in.getChannel();
// 通过输出流创建Channel
FileOutputStream out = new FileOutputStream("D://2.txt");
FileChannel outChannel = out.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(10);
// 循环操作
while (true) {
// 将数据从1.txt中读出到buffer中
int read = inChannel.read(buffer);
// read返回值为-1 表示读完了
if (read == -1) {
break;
}
// 将buffer中的数据写入到2.txt中
buffer.flip();
outChannel.write(buffer);
}
// 最后关闭Channel对象/流对象
...
// 通过输入流创建Channel
FileInputStream in = new FileInputStream("D://1.txt");
FileChannel inChannel = in.getChannel();
// 通过输出流创建Channel
FileOutputStream out = new FileOutputStream("D://3.txt");
FileChannel outChannel = out.getChannel();
// 从inChannel中把数据拷贝到outChannel中
outChannel.transferFrom(inChannel, 0, inChannel.size());
// 最后关闭Channel对象/流对象
...
// 获得一个serverSocketChannel, 注册功能在后面使用
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
// 绑定要监听的端口
serverSocketChannel.bind(new InetSocketAddress(9090));
// 设置非阻塞, 如果accept没有连接, 返回null
serverSocketChannel.configureBlocking(false);
// 循环处理获取socket
while (true) {
SocketChannel socketChannel = serverSocketChannel.accept();
if (socketChannel == null){
break;
}
// 设置socketChannel非阻塞
socketChannel.configureBlocking(false);
// 定义一个buffer
ByteBuffer buffer = ByteBuffer.allocate(1024);
// 循环读取数据, 如果1024能装下数据 只有一次循环, 否则循环拿出所有数据
while (true) {
int read = socketChannel.read(buffer);
// read == -1 表示读完了
if (read == -1) {
break;
}
// buffer反转
buffer.flip();
// 数据处理, 这里做打印
System.out.println(new String(buffer.array(),0,buffer.limit()));
}
}
