初始化缓冲区:XXXBuffer.allocate(int capacity)
数据加入缓冲区:buffer.put(byte[] data)
切换为读模式:byteBuffer.flip()
读取缓冲区中的数据:buffer.get(byte[] data)
代码示例:
package nio;
import org.junit.Test;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.util.SortedMap;
public class BufferTest {
@Test // buffer的基本使用
public void nioBufferTest(){
System.out.println("********初始化缓冲区********");
ByteBuffer byteBuffer = ByteBuffer.allocate(512); // 初始化缓冲区
System.out.println("capacity:"+byteBuffer.capacity()); // 容量
System.out.println("limit:"+byteBuffer.limit()); // 界限,可操作容量
System.out.println("position:"+byteBuffer.position()); // 正在操作的位置
System.out.println("********加入数据********");
byte[] bytes = "hello,nio".getBytes();
byteBuffer.put(bytes); // 加入数据
System.out.println("position:"+byteBuffer.position()); // position变化
System.out.println("limit:"+byteBuffer.limit()); // 不变
System.out.println("********读模式********");
byteBuffer.flip(); // 切换为读模式
System.out.println("limit:"+byteBuffer.limit()); // 加入数据字节数
System.out.println("position:"+byteBuffer.position()); // 0
System.out.println("********读取数据********");
byte[] bytes1 = "1234567".getBytes();
byteBuffer.get(bytes1);
System.out.println(new String(bytes1));
System.out.println("limit:"+byteBuffer.limit()); // 加入数据字节数
System.out.println("position:"+byteBuffer.position()); // 已读取的总长度7
byteBuffer.get("89".getBytes());
System.out.println("limit:"+byteBuffer.limit()); // 加入数据字节数
System.out.println("position:"+byteBuffer.position()); // 已读取的总长度7+2=9
System.out.println("********重复读********");
byteBuffer.rewind(); // 恢复到刚切换为读状态时的状态
System.out.println("limit:"+byteBuffer.limit()); // 加入数据字节数
System.out.println("position:"+byteBuffer.position()); // 0
System.out.println("********清空********");
byteBuffer.clear(); // 恢复到刚初始化时的状态
System.out.println("limit:"+byteBuffer.limit()); // 加入数据字节数
System.out.println("position:"+byteBuffer.position()); // 0
byteBuffer.put("1234567".getBytes());
System.out.println("********标记与reset********");
byteBuffer.flip();
byteBuffer.get(bytes1,0,4);
System.out.println(new String(bytes1, 0, 4));
System.out.println("position:"+byteBuffer.position()); // 0
byteBuffer.mark();
byteBuffer.get(bytes1,0,2);
System.out.println(new String(bytes1, 0, 2));
System.out.println("position:"+byteBuffer.position()); // 0
byteBuffer.reset();
System.out.println("position:"+byteBuffer.position()); // 0
System.out.println(byteBuffer.hasRemaining()); // 是否还有未操作数量
System.out.println(byteBuffer.remaining()); // 可操作数量
// 打印所有未操作的
if (byteBuffer.hasRemaining()) {
int n = byteBuffer.remaining();
byteBuffer.get(bytes,0,n);
System.out.println(new String(bytes, 0, n));
}
}
}
@Test // 字符集转换
public void charsetTest() throws IOException {
SortedMap<String, Charset> availableCharsets = Charset.availableCharsets();
System.out.println("********可用字符集********");
System.out.println(availableCharsets);
System.out.println("****************");
Charset gbk = Charset.forName("GBK"); // 通过名称获取字符集实例
Charset utf8 = Charset.forName("utf-8"); // 通过名称获取字符集实例
CharsetEncoder charsetEncoder = gbk.newEncoder();// 通过字符集实例获取编码器(编码:字符串-->字节数组)
CharsetDecoder charsetDecoder = utf8.newDecoder(); // 通过字符集实例获取解码器(编码:字节数组-->字符串)
CharBuffer charBuffer = CharBuffer.allocate(100);
charBuffer.put("encode decode 字符转换");
charBuffer.flip(); // 转换为读模式才可以正确执行下面的语句
ByteBuffer byteBuffer = charsetEncoder.encode(charBuffer); // 将charBuffer转换为byteBuffer
System.out.println("********ByteBuffer********");
for (int i = 0; i < byteBuffer.limit(); i++) {
System.out.print(byteBuffer.get() + " ");
}
System.out.println();
System.out.println("********CharBuffer********");
byteBuffer.flip();
CharBuffer charBuffer1 = charsetDecoder.decode(byteBuffer); // 执行报错,不能转换为utf-8
System.out.println(charBuffer1);
}
第一步:获取通道:
- fileXXXStream.getChannel()
- FileChannel fc = FileChannel.open(path,openOption)
.第二步:实例化一个/多个缓冲区,例如:
ByteBuffer bb= ByteBuffer.allocate(512);
.
第三步:数据读入通道读取数据并写入到缓冲区:
fc.read(bb);
.
第n步:用其他通道操作该缓冲区;
fcn.write(bb);
package nio;
import org.junit.Test;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class ChannelTest {
// 通道用于源节点与目标节点的连接,不负责存储
// FileChannel SocketChannel ServerSocketChannel DatagramChannel
@Test 获取通道方式一:getChannel()
public void channelTest1() {
FileInputStream fileInputStream = null; // 文件输入流,读取文件
FileOutputStream fileOutputStream = null; // 文件输出流
FileChannel fileInputStreamChannel = null; // 数据读入通道
FileChannel fileOutputStreamChannel = null; // 数据写出通道
try {
fileInputStream = new FileInputStream("yellowBoy.jpg");
fileOutputStream = new FileOutputStream("yb.jpg");
fileInputStreamChannel = fileInputStream.getChannel();
fileOutputStreamChannel = fileOutputStream.getChannel();
ByteBuffer byteBuffer = ByteBuffer.allocate(512); // 缓冲区
while (fileInputStreamChannel.read(byteBuffer) != -1) { // 数据读入通道读取数据并写入到缓冲区
byteBuffer.flip(); // 缓冲区读模式
fileOutputStreamChannel.write(byteBuffer); // 数据写出通道写入缓冲区中的数据
byteBuffer.clear(); // 清空数据,下次继续写入
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fileInputStreamChannel != null) {
fileInputStreamChannel.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (fileOutputStreamChannel != null) {
fileOutputStreamChannel.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (fileInputStream != null) {
fileInputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (fileOutputStream == null) {
fileOutputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Test 获取通道方式一:getChannel(),使用多个缓冲区
public void channelTest2() {
FileInputStream fileInputStream = null; // 文件输入流,读取文件
FileOutputStream fileOutputStream = null; // 文件输出流
FileChannel fileInputStreamChannel = null; // 数据读入通道
FileChannel fileOutputStreamChannel = null; // 数据写出通道
try {
fileInputStream = new FileInputStream("channel.txt");
fileOutputStream = new FileOutputStream("c.txt");
fileInputStreamChannel = fileInputStream.getChannel();
fileOutputStreamChannel = fileOutputStream.getChannel();
ByteBuffer byteBuffer = ByteBuffer.allocate(10); // 缓冲区
ByteBuffer byteBuffer1 = ByteBuffer.allocate(200); // 缓冲区
ByteBuffer[] byteBuffers = {byteBuffer,byteBuffer1};
while (fileInputStreamChannel.read(byteBuffers) != -1) {
fileInputStreamChannel.read(byteBuffers); // 读取数据按顺序写入到多个缓冲区(缓冲区为写模式)
System.out.println(new String(byteBuffer.array()));
byteBuffer.flip(); // 缓冲区切换为读模式
byteBuffer1.flip();
fileOutputStreamChannel.write(byteBuffers); // 从多个缓冲区读取数据写入到通道(缓冲区为读模式)
byteBuffer.clear();
byteBuffer1.clear();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fileInputStreamChannel != null) {
fileInputStreamChannel.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (fileOutputStreamChannel != null) {
fileOutputStreamChannel.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (fileInputStream != null) {
fileInputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (fileOutputStream == null) {
fileOutputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Test // FileChannel.open(),通过直接缓冲区
public void channelTest3(){
FileChannel readFileChannel = null;
FileChannel writeFileChanel = null;
try {
// 初始化一个通道,参数一:java.nio.file.Paths.get(文件路径),参数二:OpenOption
readFileChannel = FileChannel.open(Paths.get("yellowBoy.jpg"), StandardOpenOption.READ);
long size = readFileChannel.size();
writeFileChanel = FileChannel.open(Paths.get("yb.jpg"), StandardOpenOption.WRITE, StandardOpenOption.READ,StandardOpenOption.CREATE_NEW);
readFileChannel.transferTo(0,size,writeFileChanel);
// 等价
// writeFileChanel.transferFrom(readFileChannel,0,size);
// 等价
/*MappedByteBuffer readBuffer = readFileChannel.map(FileChannel.MapMode.READ_ONLY, 0,size);
MappedByteBuffer writeBuffer = writeFileChanel.map(FileChannel.MapMode.READ_WRITE, 0, size);
byte[] bytes = new byte[(int) size];
readBuffer.get(bytes);
writeBuffer.put(bytes);*/
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (writeFileChanel != null) {
writeFileChanel.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (readFileChannel != null) {
readFileChannel.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
package nio;
import org.junit.Test;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class SocketChannelTest {
@Test // 使用socketChannel进行网络编程
public void socketChannelClient() throws IOException {
// 创建SocketChannel实例
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1",33333));
// FileChannel实例用于读取本地文件
FileChannel fileChannel = FileChannel.open(Paths.get("yellowBoy.jpg"), StandardOpenOption.READ);
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
// fileChannel读取数据到byteBuffer中
while (fileChannel.read(byteBuffer)!=-1){
byteBuffer.flip();
// socketChannel读取byteBuffer中的数据并写入到socketChannel
socketChannel.write(byteBuffer);
byteBuffer.clear();
}
socketChannel.shutdownOutput(); // 告诉服务器输出完成,不然会阻塞
int len = 0;
while((len = socketChannel.read(byteBuffer))!=-1){ // socketChannel接收服务端反馈的消息
byteBuffer.flip();
System.out.println(new String(byteBuffer.array(),0,len));
byteBuffer.clear();
};
socketChannel.close();
fileChannel.close();
}
@Test
public void socketChannelServer() {
ServerSocketChannel serverSocketChannel = null;
FileChannel fileChannel = null;
SocketChannel socketChannel = null;
try {
// 服务端专用ServerSocketChannel实例
serverSocketChannel = ServerSocketChannel.open();
// 跟客户端一个道理,用于接收到客户端的文件保存到本地
fileChannel = FileChannel.open(Paths.get("boyY.jpg"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);
serverSocketChannel.bind(new InetSocketAddress(33333)); // 绑定端口,跟客户端的socketChannel同样的端口
// 接收文件,生成socketChannel实例
socketChannel = serverSocketChannel.accept();
ByteBuffer byteBuffer = ByteBuffer.allocate(512);
// 读取
while(socketChannel.read(byteBuffer)!=-1){
byteBuffer.flip();
// 写入到本地
fileChannel.write(byteBuffer);
byteBuffer.clear();
}
// 发送反馈信息
byteBuffer.put("收到了一张小黄人的图片".getBytes());
byteBuffer.flip();
socketChannel.write(byteBuffer);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socketChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
serverSocketChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
fileChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
package nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.Scanner;
public class Client {
public static void main(String[] args) throws IOException {
SocketChannel sc = SocketChannel.open(new InetSocketAddress("127.0.0.1",33333));
sc.configureBlocking(false); // 切换为非阻塞模式
ByteBuffer bb = ByteBuffer.allocate(1024);
Scanner scanner = new Scanner(System.in);
System.out.println("input: ");
while (!scanner.hasNext("exit")){ // 键盘写入,exit停止写入
String str = scanner.next();
bb.put(str.getBytes()); // 将写入的内容存储到缓冲区
bb.flip(); // 读模式
sc.write(bb); // 写入到Socket通道
bb.clear();
System.out.println("input: ");
}
System.out.println("已退出");
scanner.close();
sc.close();
}
}
package nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
ssc.bind(new InetSocketAddress(33333));
Selector selector = Selector.open(); // 获取选择器实例
ssc.register(selector,SelectionKey.OP_ACCEPT); // 注册,selector选择器监听ssc通道的accept事件
//ssc.accept(); // ssc开始accept事件,并被selector监听
while (selector.select() > 0){ // 获取selector上所有的就绪的事件个数
// 获取所有selector上所有的就绪的事件
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()){
// 一个就绪事件
SelectionKey selectionKey = iterator.next();
// 就绪事件为accept
if(selectionKey.isAcceptable()){
SocketChannel sc = ssc.accept();
sc.configureBlocking(false);
sc.register(selector,SelectionKey.OP_READ);
// 就绪事件为read
}else if (selectionKey.isReadable()){
SocketChannel selectableChannel = (SocketChannel) selectionKey.channel();
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
int len = 0;
while ((len = selectableChannel.read(byteBuffer)) > 0){
byteBuffer.flip();
System.out.println(new String(byteBuffer.array(),0,len));
byteBuffer.clear();
}
}
}
iterator.remove();
}
}
}