BIO、NIO 和 AIO 的区别、三种 IO 的用法与原理

IO
什么是 IO? 它是指计算机与外部世界或者一个程序与计算机的其余部分的之间的接
口。它对于任何计算机系统都非常关键,因而所有 I/O 的主体实际上是内置在操作系统中
的。单独的程序一般是让系统为它们完成大部分的工作。
在 Java 编程中,直到最近一直使用 流 的方式完成 I/O。所有 I/O 都被视为单个的
字节的移动,通过一个称为 Stream 的对象一次移动一个字节。流 I/O 用于与外部世界
接触。它也在内部使用,用于将对象转换为字节,然后再转换回对象。
BIO
Java BIO 即 Block I/O ,同步并阻塞的 IO。
BIO 就是传统的 java.io 包下面的代码实现。
NIO
什么是NIO? NIO 与原来的 I/O 有同样的作用和目的, 他们之间最重要的区别是数据
打包和传输的方式。原来的 I/O 以流的方式处理数据,而 NIO 以块的方式处理数据。
面向流 的 I/O 系统一次一个字节地处理数据。一个输入流产生一个字节的数据,一个
输出流消费一个字节的数据。为流式数据创建过滤器非常容易。链接几个过滤器,以便每个
过滤器只负责单个复杂处理机制的一部分,这样也是相对简单的。不利的一面是,面向流的
I/O 通常相当慢。
一个 面向块 的 I/O 系统以块的形式处理数据。每一个操作都在一步中产生或者消费
一个数据块。按块处理数据比按(流式的)字节处理数据要快得多。但是面向块的 I/O 缺少一
些面向流的 I/O 所具有的优雅性和简单性。
AIO
Java AIO 即 Async 非阻塞,是异步非阻塞的 IO。 205
>
I/O
区别及联系
BIO (Blocking I/O):同步阻塞 I/O 模式,数据的读取写入必须阻塞在一个线程内
等待其完成。这里假设一个烧开水的场景,有一排水壶在烧开水,BIO 的工作模式就是,
叫一个线程停留在一个水壶那,直到这个水壶烧开,才去处理下一个水壶。但是实际上线程
在等待水壶烧开的时间段什么都没有做。
NIO (New I/O):同时支持阻塞与非阻塞模式,但这里我们以其同步非阻塞 I/O 模
式来说明,那么什么叫做同步非阻塞?如果还拿烧开水来说,NIO 的做法是叫一个线程不
断的轮询每个水壶的状态,看看是否有水壶的状态发生了改变,从而进行下一步的操作。
AIO ( Asynchronous I/O):异步非阻塞 I/O 模型。异步非阻塞与同步非阻塞的区
别在哪里?异步非阻塞无需一个线程去轮询所有 IO 操作的状态改变,在相应的状态改变后,
系统会通知对应的线程来处理。对应到烧开水中就是,为每个水壶上面装了一个开关,水烧
开之后,水壶会自动通知我水烧开了。
各自适用场景
BIO 方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,
并发局限于应用中,JDK1.4 以前的唯一选择,但程序直观简单易理解。
NIO 方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发
局限于应用中,编程比较复杂,JDK1.4 开始支持。
AIO 方式适用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分
调用 OS 参与并发操作,编程比较复杂,JDK7 开始支持。
使用方式
使用 BIO 实现文件的读取和写入。
//Initializes The Object
User1 user = new User1();
user.setName("hollis");
user.setAge(23);
System.out.println(user); I/O <
206
//Write Obj to File
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("tempFile"));
oos.writeObject(user);
} catch (IOException e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(oos);
}
//Read Obj from File
File file = new File("tempFile");
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream(file));
User1 newUser = (User1) ois.readObject();
System.out.println(newUser);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(ois);
try {
FileUtils.forceDelete(file);
} catch (IOException e) {
e.printStackTrace();
}
}
使用 NIO 实现文件的读取和写入。
static void readNIO() {
String pathname = "C:\\Users\\adew\\Desktop\\jd-gui.cfg";
FileInputStream fin = null;
try {
fin = new FileInputStream(new File(pathname));
FileChannel channel = fin.getChannel();
int capacity = 100;// 字节
ByteBuffer bf = ByteBuffer.allocate(capacity);
System.out.println(" 限制是: " + bf.limit() + " 容量是: " + bf.capacit
y()
+ " 位置是: " + bf.position());
int length = -1;
while ((length = channel.read(bf)) != -1) { 207
>
I/O
/*
* 注意,读取后,将位置置为 0 ,将 limit 置为容量 , 以备下次读入到字节缓冲中,
0 开始存储
*/
bf.clear();
byte[] bytes = bf.array();
System.out.write(bytes, 0, length);
System.out.println();
System.out.println(" 限制是: " + bf.limit() + " 容量是: " + bf.capa
city()
+ " 位置是: " + bf.position());
}
channel.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fin != null) {
try {
fin.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
static void writeNIO() {
String filename = "out.txt";
FileOutputStream fos = null;
try {
fos = new FileOutputStream(new File(filename));
FileChannel channel = fos.getChannel();
ByteBuffer src = Charset.forName("utf8").encode(" 你好你好你好你好你
");
// 字节缓冲的容量和 limit 会随着数据长度变化,不是固定不变的
System.out.println(" 初始化容量和 limit " + src.capacity() + ","
+ src.limit());
int length = 0;
while ((length = channel.write(src)) != 0) {
/*
* 注意,这里不需要 clear ,将缓冲中的数据写入到通道中后 第二次接着上一次
的顺序往下读
*/ I/O <
208
System.out.println(" 写入长度 :" + length);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
使用 AIO 实现文件的读取和写入。
public class ReadFromFile {
public static void main(String[] args) throws Exception {
Path file = Paths.get("/usr/a.txt");
AsynchronousFileChannel channel = AsynchronousFileChannel.open(file);
ByteBuffer buffer = ByteBuffer.allocate(100_000);
Future< Integer > result = channel.read(buffer, 0);
while (!result.isDone()) {
ProfitCalculator.calculateTax();
}
Integer bytesRead = result.get();
System.out.println("Bytes read [" + bytesRead + "]");
}
}
class ProfitCalculator {
public ProfitCalculator() {
}
public static void calculateTax() {
}
}
public class WriteToFile {
public static void main(String[] args) throws Exception {
AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(
Paths.get("/asynchronous.txt"), StandardOpenOption.READ,
StandardOpenOption.WRITE, StandardOpenOption.CREATE);
CompletionHandler< Integer, Object > handler = new CompletionHandler< Inte
ger, Object >() { 209
>
I/O
@Override
public void completed(Integer result, Object attachment) {
System.out.println("Attachment: " + attachment + " " + result
+ " bytes written");
System.out.println("CompletionHandler Thread ID: "
+ Thread.currentThread().getId());
}
@Override
public void failed(Throwable e, Object attachment) {
System.err.println("Attachment: " + attachment + " failed with:");
e.printStackTrace();
}
};
System.out.println("Main Thread ID: " + Thread.currentThread().getId
());
fileChannel.write(ByteBuffer.wrap("Sample".getBytes()), 0, "First Write
",
handler);
fileChannel.write(ByteBuffer.wrap("Box".getBytes()), 0, "Second Write",
handler);
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值