NIO_缓冲区和通道
程序员文章站
2024-02-29 23:13:46
...
Java在1.5之后提供了新的IO通信框架,NIO和普通IO的区别是NIO是基于channel和Buffer来进行操作的,这和传统的IO是有一些区别的,传统的IO是基于管道流的方式进行数据传输,而NIO的数据首先需要添加到buffer中,之后通过channel来进行传输。
Buffer缓冲区
不同的数据类型都是自己的缓冲区,但是在NIO中比较通用的是ByteBuffer,通过allocate和allocateDirect来创建缓冲区,第一种缓冲区是在堆中创建,第二种缓冲区会在操作系统的内存中创建,第二种缓冲区占用的是系统的内存资源,创建和销毁都需要一定的开销,在使用channel的时候能够提高一定的效率。
Channel
NIO中是通过Channel来传输buffer的数据,操作和IO类似,但多了将Buffer添加到Channel的步骤
一个读取文件的实例:
public class TestChannel {
public static void main(String[] args) {
FileChannel fc = null;
try {
// 创建文件管道
fc = FileChannel.open(Paths.get("d:/data/11.txt"), StandardOpenOption.READ);
// 创建buffer
ByteBuffer buffer = ByteBuffer.allocate(1024);
int len = 0;
byte[] buf = new byte[1024];
// 只要能够从缓冲区中读取数据
while ((len = fc.read(buffer)) > 0) {
// 重置缓冲区
buffer.flip();// nio中提供了flip()方法来反转缓冲区,反转之后limit会指向当前缓冲区的最大值。
// 从缓冲区读取到字节数组中
buffer.get(buf, 0, len);
// 输出字节数组的值
System.out.println(new String(buf, 0, len));
// 重置缓冲区
buffer.clear();
}
// fc.read(buffer);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fc != null)
fc.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
实现文件copy 的实例
public class TestChannel02 {
public static void main(String[] args) {
FileChannel fin = null;
FileChannel fout = null;
ByteBuffer buf = null;
try {
//创建两个通道,一个读数据,一个写数据
fin = FileChannel.open(Paths.get("d:/data/aa.txt"), StandardOpenOption.READ);
//设置文件如果不存在就创建,并且可以进行写操作
fout = FileChannel.open(Paths.get("d:/data/bb.txt"),StandardOpenOption.CREATE,StandardOpenOption.WRITE);
//创建缓冲区来作为数据的中转
buf = ByteBuffer.allocate(1024);
while((fin.read(buf))>0) {
buf.flip();
fout.write(buf);
buf.clear();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(fin!=null) fin.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(fout!=null) fout.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
在NIO中提供了transferTo方法来快速将两个通道进行转换
public class TestChannel03 {
public static void main(String[] args) {
FileChannel fin = null;
FileChannel fout = null;
try {
fin = FileChannel.open(Paths.get("d:/data/aa.txt"), StandardOpenOption.READ);
fout = FileChannel.open(Paths.get("d:/data/bb.txt"), StandardOpenOption.CREATE_NEW,
StandardOpenOption.WRITE);
// 通过transferTo可以将两个通道对接
fin.transferTo(0, fin.size(), fout);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fin != null)
fin.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (fout != null)
fout.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
NIO主要基于网络通信中
传统的 io 和 NIO 的区别,通过见图表达
以下是NIO 的网络编程实例
public class NioSocketDemo {
private Selector selector;
public static void main(String[] args) throws IOException {
NioSocketDemo nd = new NioSocketDemo();
nd.initServer(8888);
nd.listenSelector();
}
public void initServer(int port) throws IOException {
ServerSocketChannel schannel = ServerSocketChannel.open();
schannel.configureBlocking(false);
schannel.socket().bind(new InetSocketAddress(port));
this.selector = Selector.open();
schannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("服务已经启动了");
}
public void listenSelector() throws IOException {
while (true) {
this.selector.select();// 阻塞点 真正关心的阻塞点是读取数据
Iterator<SelectionKey> set = selector.selectedKeys().iterator();
while (set.hasNext()) {
SelectionKey key = set.next();
set.remove();
handler(key);
}
}
}
private void handler(SelectionKey key) throws IOException {
if (key.isAcceptable()) {
ServerSocketChannel serverChanel = (ServerSocketChannel) key.channel();
SocketChannel sc = serverChanel.accept();
sc.configureBlocking(false);// 设置非阻塞,
sc.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
SocketChannel sc = (SocketChannel) key.channel();
ByteBuffer bb = ByteBuffer.allocate(1024);
int c = sc.read(bb);
if (c > 0) {
String str = new String(bb.array(), "GBK").trim();
System.out.println("服务端收到数据:" + str);
} else {
System.out.println("客户端关闭了......");
key.cancel();
}
}
}
}
推荐阅读
-
NIO_缓冲区和通道
-
清理输入和输出缓冲区 stdin&stdout
-
某8253的端口地址为84H~87H,其中,87H为控制口,84H~86H分别为通道0、通道1和通道2。
-
InterBase和Firebird远程栈缓冲区溢出漏洞
-
Python IO操作文件读取和写入、open函数的mode参数、buffering,文件缓冲区
-
Python3: 内存中的 IO 流缓冲区 - StringIO 和 BytesIO
-
BitTorrent和uTorrent Peers 窗口缓冲区溢出漏洞
-
双通道和双核的应用技术与含义大揭密!
-
Photoshop利用通道和滤镜制作逼真的下雨GIF动画
-
Photoshop利用通道和计算命令抠出复杂物体的实例教程