漫画:一文学会面试中常问的 IO 问题!


作者?| 漫话编程
责编 | 伍杏玲
本文经授权转载自漫话编程(ID:mhcoding)
周末午后,在家里面进行电话面试,我问了面试者几个关于IO的问题,其中包括什么是BIO、NIO和AIO?三者有什么区别?具体如何使用等问题,但是面试者回答的并不是很满意。于是我在面试评价中写道:"对Java的IO提醒理解不够深入"。恰好被女朋友看到了。





Java IO
IO,常协作I/O,是Input/Output的简称,即输入/输出。通常指数据在内部存储器(内存)和外部存储器(硬盘、优盘等)或其他周边设备之间的输入和输出。
输入/输出是信息处理系统(例如计算机)与外部世界(可能是人类或另一信息处理系统)之间的通信。
输入是系统接收的信号或数据,输出则是从其发送的信号或数据。
在Java中,提供了一些列API,可以供开发者来读写外部数据或文件。我们称这些API为Java IO。
IO是Java中比较重要,且比较难的知识点,主要是因为随着Java的发展,目前有三种IO共存。分别是BIO、NIO和AIO。




Java BIO、NIO
BIO 全称Block-IO 是一种同步且阻塞的通信模式。是一个比较传统的通信方式,模式简单,使用方便。但并发处理能力低,通信耗时,依赖网速。
Java NIO,全程 Non-Block IO ,是Java SE 1.4版以后,针对网络传输效能优化的新功能。是一种非阻塞同步的通信模式。
NIO 与原来的 I/O 有同样的作用和目的, 他们之间最重要的区别是数据打包和传输的方式。原来的 I/O 以流的方式处理数据,而 NIO 以块的方式处理数据。
面向流的 I/O 系统一次一个字节地处理数据。一个输入流产生一个字节的数据,一个输出流消费一个字节的数据。
面向块的 I/O 系统以块的形式处理数据。每一个操作都在一步中产生或者消费一个数据块。按块处理数据比按(流式的)字节处理数据要快得多。但是面向块的 I/O 缺少一些面向流的 I/O 所具有的优雅性和简单性。

Java AIO
Java AIO,全程 Asynchronous IO,是异步非阻塞的IO。是一种非阻塞异步的通信模式。
在NIO的基础上引入了新的异步通道的概念,并提供了异步文件通道和异步套接字通道的实现。





三种IO的区别
首先,我们站在宏观的角度,重新画一下重点:
BIO (Blocking I/O):同步阻塞I/O模式。
NIO (New I/O):同步非阻塞模式。
AIO (Asynchronous I/O):异步非阻塞I/O模型。
那么,同步阻塞、同步非阻塞、异步非阻塞都是怎么回事呢?关于这部分内容也可以查看《漫话:如何给女朋友解释什么是IO中的阻塞、非阻塞、同步、异步?》。
同步阻塞模式:这种模式下,我们的工作模式是先来到厨房,开始烧水,并坐在水壶面前一直等着水烧开。
同步非阻塞模式:这种模式下,我们的工作模式是先来到厨房,开始烧水,但是我们不一直坐在水壶前面等,而是回到客厅看电视,然后每隔几分钟到厨房看一下水有没有烧开。
异步非阻塞I/O模型:这种模式下,我们的工作模式是先来到厨房,开始烧水,我们不一一直坐在水壶前面等,也不隔一段时间去看一下,而是在客厅看电视,水壶上面有个开关,水烧开之后他会通知我。
阻塞VS非阻塞:人是否坐在水壶前面一直等。
同步VS异步:水壶是不是在水烧开之后主动通知人。





适用场景
BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解。
NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。
AIO方式适用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。



使用方式
分别使用BIO、NIO、AIO 实现文件的读取和写入:
//Initializes?The?Object
User1?user?=?new?User1();
user.setName("hollis");
user.setAge(23);
System.out.println(user);
//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();
????}
}
//Initializes?The?Object
User1?user?=?new?User1();
user.setName("hollis");
user.setAge(23);
System.out.println(user);
//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();
????}
}
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);
????????????int?length?=?-1;
????????????while?((length?=?channel.read(bf))?!=?-1)?{
????????????????bf.clear();
????????????????byte[]?bytes?=?bf.array();
????????????????System.out.write(bytes,?0,?length);
????????????????System.out.println();
????????????}
????????????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("你好你好你好你好你好");
????????????int?length?=?0;
????????????while?((length?=?channel.write(src))?!=?0)?{
????????????????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();
????????????????}
????????????}
????????}
????}
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?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 ?handler?=?new?CompletionHandler ()?{
??????@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);
??}
}




滴滴滴,水开了。




?热 文?推 荐?
?独家 | Vitalik Buterin:以太坊2.0之跨分片交易
?面试官:你简历中写用过docker,能说说容器和镜像的区别吗?
?C++、Python、Rust、Scala构建编译器的差异性究竟有多大?

关注公众号:拾黑(shiheibook)了解更多
[广告]赞助链接:
四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/
关注网络尖刀微信公众号随时掌握互联网精彩
- 1 习近平将发表二〇二六年新年贺词 7904141
- 2 2026年国补政策来了 7808738
- 3 东部战区:开火!开火!全部命中! 7712893
- 4 2026年这些民生政策将惠及百姓 7616985
- 5 小学食堂米线过期2.5小时被罚5万 7519709
- 6 解放军喊话驱离台军 原声曝光 7428214
- 7 为博流量直播踩烈士陵墓?绝不姑息 7327605
- 8 每月最高800元!多地发放养老消费券 7238391
- 9 数字人民币升级 1月1日起将计付利息 7141831
- 10 2026年1月1日起 一批新规将施行 7040675


程序人生
