飞道的博客

JAVA BIO 笔记

377人阅读  评论(0)

什么是 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
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场