什么是 BIO?
实际上是对应的是java.io。那为什么是BIO呢?
原来是因为Java有好几个IO,为了弥补和改善,又出了NIO,AIO。那么为了区别开分,就把原先最早的叫做BIO(Blocking IO)。
BIO 包括跟些东西?
上大图(来自百度图片)
字节流:
以字节为单位,字节流用来处理二进制文件,例如图片、MP3、视频文件。(电脑 识别的)
字符流:
以字符为单位,一个字符根据编码的不同,对应的字节也不同,如 UTF-8 编码是 3 个字节,中文编码是 2 个字节。主要用于文本,文档(使用了某种编码,人可以阅读)。
应用场景
1读取控制台中的输入
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Test1 {
public static void main(String[] args) throws IOException {
test();
}
public static void test() throws IOException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入");
String str = bufferedReader.readLine();
System.out.println("你输入的是:" + str);
}
}
二进制文件的写入和读取
**写入:**把一下数组用二进制的方法写入到文本里面。
import java.io.*;
public class Test2 {
public static void main(String[] args) throws IOException {
byte[] bytes = {12,21,34,11,21};
String path=new File("").getAbsolutePath()+"/test.txt";
System.out.println(path);
FileOutputStream fileOutputStream = new FileOutputStream(path);
// 写入二进制文件,直接打开会出现乱码
fileOutputStream.write(bytes);
fileOutputStream.close();
}
}
输出的文件用文本打开是乱码,如下图所示。
**读取:**上面写入的例子,用二进制的方法把它读出来,并还原内容。
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Test3 {
public static void main(String[] args) throws IOException {
String path=new File("").getAbsolutePath()+"/test.txt";
System.out.println(path);
FileInputStream fileInputStream = new FileInputStream(path);
int c;
// 读取写入的二进制文件,输出字节数组
while ((c = fileInputStream.read()) != -1) {
System.out.print(c+" ");
}
}
}
结果如下:
文本文件的写入和读取
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
public class Test4 {
public static void main(String[] args) throws IOException {
String path=new File("").getAbsolutePath()+"/test2.txt";
System.out.println("路径:"+path);
FileWriter fileWriter = new FileWriter(path);
System.out.println("文件的默认编码为" + fileWriter.getEncoding());
fileWriter.write("Hello,world!\n欢迎来到 java 世界\n");
fileWriter.flush();
fileWriter.close();
}
}
结果如下图:
public class Test5 {
public static void main(String[] args) throws IOException {
String path=new File("").getAbsolutePath()+"/test2.txt";
System.out.println("路径:"+path);
FileReader fileReader = new FileReader(path);
BufferedReader bufferedReader = new BufferedReader(fileReader);
String str;
while ((str = bufferedReader.readLine()) != null) {
System.out.println(str);
}
fileReader.close();
bufferedReader.close();
}
}
读取:
import java.io.*;
public class Test5 {
public static void main(String[] args) throws IOException {
String path=new File("").getAbsolutePath()+"/test2.txt";
System.out.println("路径:"+path);
FileInputStream fileInputStream = new FileInputStream(path);
//上面的测试使用的是UTF-8
InputStreamReader fileReader =new InputStreamReader(fileInputStream,"UTF-8");
BufferedReader bufferedReader = new BufferedReader(fileReader);
String str;
while ((str = bufferedReader.readLine()) != null) {
System.out.println(str);
}
fileReader.close();
bufferedReader.close();
}
}
结果如下:
大文件复制: 使用了缓存。一般定义缓存都是4K的整数倍,因为硬盘的一叶就是4K。
import java.io.*;
public class Test6 {
public static void main(String[] args) throws IOException {
// 输入和输出都使用缓冲流
FileInputStream in = new FileInputStream("E:\\迅雷下载\\video\\ADN-216.mp4");
BufferedInputStream inBuffer = new BufferedInputStream(in);
FileOutputStream out = new FileOutputStream("E:\\迅雷下载\\video\\新闻联播.mp4");
BufferedOutputStream outBuffer = new BufferedOutputStream(out);
int len = 0;
//注意为什么缓存普遍都用的是4000。因一硬盘的的一页就是4K个字节。
byte[] bs = new byte[4000];
long begin = System.currentTimeMillis();
while ((len = inBuffer.read(bs)) != -1) {
outBuffer.write(bs, 0, len);
}
System.out.println("复制文件所需的时间:" + (System.currentTimeMillis() - begin)); // 平均时间约 200 多毫秒
inBuffer.close();
in.close();
outBuffer.close();
out.close();
}
}
配合Socket 的IO
模拟AB个应用使用TCP/IP 连接,然后聊天。
服务端
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerMain {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(4700);
Socket socket = ss.accept();
PrintWriter os=new PrintWriter(socket.getOutputStream());
BufferedReader br =new BufferedReader(new InputStreamReader(System.in) );
BufferedReader is =new BufferedReader(new InputStreamReader(socket.getInputStream()) );
new Thread( ()->{
while (true) {
try {
System.out.println( is.readLine());
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
while (true) {
String str=br.readLine();
os.println(str);
os.flush();
}
}
}
客户端
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class ClientMain {
public static void main (String[] args) throws IOException {
Socket socket =new Socket("127.0.0.1",4700);
PrintWriter os=new PrintWriter(socket.getOutputStream());
BufferedReader br =new BufferedReader(new InputStreamReader(System.in) );
BufferedReader is =new BufferedReader(new InputStreamReader(socket.getInputStream()) );
new Thread( ()->{
while (true) {
try {
System.out.println( is.readLine());
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
while (true) {
String str=br.readLine();
os.println(str);
os.flush();
}
}
}
缺陷
BIO是阻塞的IO,阻塞是什么意思?举个例子,一个文件在同一时间只能被一个线程读取或写入,文件被A线程独占了,如线程B在同一时间访问,将会进入等待,一直等到线程A释放。
那么进入等待的行为就是阻塞。如下图所示。
阻塞带来什么问题?
1:没办法发挥多线程的优势。
2:当并发量上来的时候,阻塞可能导饥饿,一堆线程得不到IO,进入等待。然后导致线程越来越多,实际上线程的开销是很大的,JVM专门为线程分配内存(TLAB)。
既然BIO有这么大的问题,那应该有什么改进的方案?是的,NIO与AIO。
未完待续。
转载:https://blog.csdn.net/richyliu44/article/details/105669048
查看评论