IO 是 Input/Output 的简称,经常写作 I/O 即输入/输出。通常指数据在内存和硬盘之间的输入和输出。
输入/输出是信息处理系统与外部世界之间的通信,比如计算机和人类之间。
输入是系统接收的信号或数据,输出则是从其发送的信号或数据。
JAVA 中提供了一些 API,可以提供开给发者来读写外部数据或文件,通常称这些 API 为 Java IO。
随着JAVA 的不断发展,目前有三种 IO ,分别是 BIO、NIO、AIO。
BIO 全称 Block-IO 是一种同步阻塞的通信模式。是一个比较传统的通信方式,该模式实现起来简单方便,但通信耗时并且并发处理能力低下。
即 JAVA 中的 NIO( Non-Block IO ),是一种非同步阻塞的通信模式。它是 JAVA SE 1.4 版本之后针对网络传输效能优化的新功能。
NIO 与原来的 I/O 一样, 他们之间最重要的区别是数据打包和传输方式上的不同。原来的 I/O 以流的方式处理数据,而 NIO 以块的方式处理数据。
面向流的 I/O 系统以一次一个字节的方式处理数据。一个输入流产生一个字节的数据,一个输出流消费一个字节的数据。
面向块的 I/O 系统以块的形式处理数据。每一个操作都在一步中产生或者消费一个数据块。按块处理数据比按(流式的)字节处理数据要快得多。但是面向块的 I/O 实现起来没有面向流的简单。
即 JAVA 中的 AIO(Asynchronous IO),是异步非阻塞的通信模式。
在 NIO 的基础上引入了异步通道的概念,并提供了异步文件通道和异步套接字通道的实现。
用洗衣机洗衣服的场景来举例:
BIO方式:适用于连接数比较小的架构,这种方式对服务器资源要求比较高并且并发支持比较局限,是 JDK1.4 以前的唯一选择,但好处是程序代码直观简单易理解。
NIO方式:适用于连接数多且连接比较短的架构,比如 IM 即时通讯,但是编程比较复杂,JDK1.4 开始支持。
AIO方式:适用于连接数多且连接比较长的架构,比如文件服务器,调用操作系统参与并发操作让编程更加复杂,JDK7 开始支持。
//1.初始化对象
User user = new User();
user.setName("gwx");
user.setAge(18);
//2.将对象写入文件
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("userObjectFile"));
oos.writeObject(user);
} catch (Exception e) {
// 打印日志
} finally {
// 关闭资源
}
//3.从文件读取对象
File file = new File("userObjectFile");
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream(file));
User newUser = (User) ois.readObject();
} catch (Exception e) {
// 打印日志
} finally {
// 关闭资源
}
// 1.读文件
static void readNIO() {
String pathname = "/Users/gwx/input.txt";
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);
}
channel.close();
} catch (FileNotFoundException e) {
// 打印日志
} catch (IOException e) {
// 打印日志
} finally {
if (fin != null) {
try {
fin.close();
} catch (IOException e) {
// 打印日志
}
}
}
}
//2.写文件
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) {
// 打印日志
} catch (IOException e) {
// 打印日志
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
// 打印日志
}
}
}
}
/**
* 1.读文件
*/
public class ReadFromFile {
public static void main(String[] args) throws Exception {
Path file = Paths.get("/Users/gwx/input.txt");
AsynchronousFileChannel channel = AsynchronousFileChannel.open(file);
// 100_000==100000,加下划线是为了易读
ByteBuffer buffer = ByteBuffer.allocate(100_000);
Future<Integer> result = channel.read(buffer, 0);
while (!result.isDone()) {
//打印日志
}
Integer bytesRead = result.get();
}
}
/**
* 2.写文件
*/
public class WriteToFile {
public static void main(String[] args) throws Exception {
AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(
Paths.get("/output.txt"), StandardOpenOption.READ,
StandardOpenOption.WRITE, StandardOpenOption.CREATE);
CompletionHandler<Integer, Object> handler = new CompletionHandler<Integer, Object>() {
@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("主线程id为: " + Thread.currentThread().getId());
fileChannel.write(ByteBuffer.wrap("第一次写".getBytes()), 0, "第一次写...",
handler);
fileChannel.write(ByteBuffer.wrap("第二次写".getBytes()), 0, "第二次写...",
handler);
}
}