NIO特点
- 使用
Channel
代替Stream
,是双向的 - 使用
Selector
监控多条Channel
- 可以在一个线程里处理多个
Channel I/O
Channel和Buffer
Buffer
应用程序对Channel的读写必须通过Buffer。Buffer实质上是一个数组,通常是字节数组,JAVA中的八种基本类型都有各自对应的Buffer。
Buffer包含三个指针:
- capacity:最大容量
- limit:限制位置
- position:要操作的位置
Buffer既可以读也可以写,但读和写之间必须进行模式切换,常用API:
flip():
翻转模式:写模式->读模式
把position还原回初始位置,limit指针指向刚才position指向的位置。position和limit之间即为要读的数据。
clear():
翻转模式:写模式->读模式
n
position还原初始位置,limit指向capacity。
compact():
翻转模式:写模式->读模式
如果只读取了一部分,剩下的一部分以后再读:把未读取的数据拷贝到最开始的位置,position指向未读数据后面的位置,limit指向capacity
Channel
通道之间进行数据的传输,类似于Stream,可不经过Buffer之间transfer数据
主要有如下几种Channel
- FileChannel
- ServerSocketChannel
- SocketChannel
NIO和BIO实现文件的复制
声明接口:
interface FileCopyRunner{
void copyFile(File source, File target);
}
关闭资源方法:
private static void close(Closeable... closeable){
for(Closeable c:closeable){
try {
c.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
BIO,不使用缓冲流:
FileCopyRunner noBufferStreamCopy = new FileCopyRunner() {
@Override
public void copyFile(File source, File target) {
InputStream fin = null;
OutputStream fout = null;
try {
fin = new FileInputStream(source);
fout = new FileOutputStream(target);
int result;
while((result = fin.read())!=-1){
fout.write(result);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
close(fin,fout);
}
}
@Override
public String toString() {
return "noBufferStreamCopy";
}
};
BIO,使用缓冲流:
FileCopyRunner bufferedStreamCopy = new FileCopyRunner() {
@Override
public void copyFile(File source, File target) {
InputStream fin = null;
OutputStream fout = null;
try {
fin = new BufferedInputStream(new FileInputStream(source));
fout = new BufferedOutputStream(new FileOutputStream(target));
byte[] buffer = new byte[1024];
int result;
while((result = fin.read(buffer))!=-1){
fout.write(buffer,0,result);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
close(fin,fout);
}
}
@Override
public String toString() {
return "bufferedStreamCopy";
}
};
NIO,经过Buffer:
FileCopyRunner nioBufferCopy = new FileCopyRunner() {
@Override
public void copyFile(File source, File target) {
FileChannel fin = null;
FileChannel fout = null;
try {
fin = new FileInputStream(source).getChannel();
fout = new FileOutputStream(target).getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
while (fin.read(buffer)!=-1){
buffer.flip();
while (buffer.hasRemaining()){
fout.write(buffer);
}
buffer.clear();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
close(fin,fout);
}
}
@Override
public String toString() {
return "nioBufferCopy";
}
};
NIO,不经过Buffer:
FileCopyRunner nioTransferCopy = new FileCopyRunner() {
@Override
public void copyFile(File source, File target) {
FileChannel fin = null;
FileChannel fout = null;
try {
fin = new FileInputStream(source).getChannel();
fout = new FileOutputStream(target).getChannel();
long transferred = 0L;
long size = fin.size();
while (transferred!=size) {
transferred += fin.transferTo(0,size,fout);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
close(fin,fout);
}
}
@Override
public String toString() {
return "nioTransferCopy";
}
};
可以编写函数进行性能测试:
private static final int ROUNDS = 5;
private static void benchmark(FileCopyRunner test,File source,File target){
long elapsed = 0L;
for(int i = 0;i<ROUNDS;i++){
long startTime = System.currentTimeMillis();
test.copyFile(source,target);
elapsed += System.currentTimeMillis() - startTime;
target.delete();
}
System.out.println(test+":"+elapsed/ROUNDS);
}
原创文章,作者:彭晨涛,如若转载,请注明出处:https://www.codetool.top/article/nio%e3%80%81bio%e6%a8%a1%e5%9e%8b%e5%af%b9%e6%af%94%e5%ae%9e%e7%8e%b0%e6%96%87%e4%bb%b6%e7%9a%84%e5%a4%8d%e5%88%b6/