Java IO流是用于处理输入和输出的机制,用于读取和写入数据。Java提供了丰富的IO类和接口,用于处理不同类型的数据和操作。Java中的IO模型主要分为BIO和NIO两种,他们可以分别被视为IO编程的不同风格或模式,并非IO流具体的类型,主要为BIO,NIO和AIO(NIO的升级版)。这篇我们主要围绕BIO进行,介绍BIO的相关使用和案例。
BIO
是传统的阻塞式IO模型,基于流的概念,使用阻塞的方式进行IO操作,在BIO模型中,当一个线程执行IO操作的时候,会被阻塞,直到数据准备好或者操作完成,这意味着一个线程只能处理一个IO操作,如果有多个IO操作需要处理,就需要创建多个线程,这样就导致资源的方法和性能下降。
BIO的相关特点:
-
阻塞等待:当没有数据可读取时,BIO模型会阻塞线程,直到有数据可读取。同样,当无法写入数据时,BIO模型会阻塞线程,直到有空闲的写入缓冲区。
-
同步阻塞:BIO模型是同步阻塞的,即一个线程只能处理一个IO操作。如果有多个IO操作需要处理,就需要创建多个线程,这可能导致资源浪费和性能下降。
-
适用于连接数较少:由于每个IO操作都需要一个独立的线程来处理,BIO模型适用于连接数较少的场景。当连接数增加时,线程数量也会增加,可能导致系统资源消耗过大。
由于BIO会阻塞进程,故而其不适用于高并发场景,即便可以使用线程池进行相关优化,但是他还会消耗线程资源,与此同时,在百万级别的并发场景下也撑不住。
BIO的类型
IO流中具有很多种类型,我们这里重点围绕字符流和字节流进行。每种类型都有输入流和输出流的概念,用于处理不同类型的数据。
字节流:
- InputStream:字节输入流的抽象基类,用于从数据源读取字节。
- OutputStream:字节输出流的抽象基类,用于向目标写入字节。
- FileInputStream:文件字节输入流,用于从文件中读取字节。
- FileOutputStream:文件字节输出流,用于向文件中写入字节。
- ByteArrayInputStream:字节数组输入流,用于从内存中读取字节。
- ByteArrayOutputStream:字节数组输出流,用于向内存中写入字节。
字符流:
- Reader:字符输入流的抽象基类,用于从数据源读取字符。
- Writer:字符输出流的抽象基类,用于向目标写入字符。
- FileReader:文件字符输入流,用于从文件中读取字符。
- FileWriter:文件字符输出流,用于向文件中写入字符。
- StringReader:字符串字符输入流,用于从字符串中读取字符。
- StringWriter:字符串字符输出流,用于向字符串中写入字符。
除了字节流和字符流,还有一些其他类型的IO流,如对象流、缓冲流、数据流等,它们提供了更高级的功能和特定的数据处理方式。
JavaIO流的相关概念和常用类
字节流和字符流:
- 字节流:以字节为单位进行读写操作,适用于处理二进制数据。常见的字节流类有
InputStream
和OutputStream
。 - 字符流:以字符为单位进行读写操作,适用于处理文本数据。常见的字符流类有
Reader
和Writer
。
节点流和处理流:
- 节点流:直接与数据源或目标进行交互,如文件、网络连接等。常见的节点流类有
FileInputStream
、FileOutputStream
、FileReader
和FileWriter
。 - 处理流:对节点流进行包装,提供额外的功能,如缓冲、压缩、加密等。常见的处理流类有
BufferedInputStream
、BufferedOutputStream
、BufferedReader
和BufferedWriter
。
输入流和输出流:
- 输入流:用于从数据源读取数据的流。常见的输入流类有
InputStream
和Reader
。 - 输出流:用于向目标写入数据的流。常见的输出流类有
OutputStream
和Writer
。
常用IO类:
File
:用于操作文件和目录。ByteArrayInputStream
和ByteArrayOutputStream
:用于在内存中读写字节数组。StringReader
和StringWriter
:用于在内存中读写字符串。ObjectInputStream
和ObjectOutputStream
:用于读写Java对象。
示例:
import java.io.*;
public class IOExample {
public static void main(String[] args) {
try {
// 创建输入流
FileInputStream fis = new FileInputStream("input.txt");
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader br = new BufferedReader(isr);
// 创建输出流
FileOutputStream fos = new FileOutputStream("output.txt");
OutputStreamWriter osw = new OutputStreamWriter(fos);
BufferedWriter bw = new BufferedWriter(osw);
// 读取输入流并写入输出流
String line;
while ((line = br.readLine()) != null) {
bw.write(line);
bw.newLine();
}
// 关闭流
br.close();
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
在这个示例中,我们使用了字符流和缓冲流来读取一个文本文件的内容,并将内容写入另一个文本文件。首先,我们创建了输入流和输出流的实例,然后使用缓冲流逐行读取输入流的内容,并将内容写入输出流。最后,我们关闭流以释放资源。
案例2
我们在利用BIO模型和JavaSocket创建一个服务器和客户端进行交互的案例。
服务端代码:
public class BIOServerExample {
public static void main(String[] args) {
try {
// 创建ServerSocket并监听端口
ServerSocket serverSocket = new ServerSocket(8082);
System.out.println("服务启动,监听到端口号为:"+ serverSocket.getLocalPort());
while (true) {
// 等待客户端连接
Socket socket = serverSocket.accept();
System.out.println("客户端链接成功: " + socket.getInetAddress());
// 创建输入流和输出流
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
// 读取客户端发送的数据
byte[] buffer = new byte[1024];
int length = inputStream.read(buffer);
String request = new String(buffer, 0, length);
System.out.println("接受请求: " + request);
// 处理请求并发送响应
String response = "Hello, " + request;
outputStream.write(response.getBytes());
// 关闭连接
socket.close();
System.out.println("客户端断开链接.");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端代码:
public class BIOClientExample {
public static void main(String[] args) {
try {
// 创建Socket并连接服务器
Socket socket = new Socket("localhost", 8082);
System.out.println("链接去服务: " + socket.getInetAddress());
// 创建输入流和输出流
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
// 发送请求
String request = "World";
outputStream.write(request.getBytes());
// 接收响应
byte[] buffer = new byte[1024];
int length = inputStream.read(buffer);
String response = new String(buffer, 0, length);
System.out.println("接收响应: " + response);
// 关闭连接
socket.close();
System.out.println("从服务器断开链接.");
} catch (IOException e) {
e.printStackTrace();
}
}
}