IO流详解——Robyn编程学习(Java)

为什么要学习IO流

文件在程序中是以流的形式来操作的(流也是Java程序和磁盘文件交互的方式)

IO流则是针对程序而已,I是输入,O是输出

IO流的知识体系

字节流与字符流

  • 字节流输入:FileInputStream
 public void readFile02() {
        String filePath = "F:\\hello.txt";
        //定义一个字节数组(一次读取8个字节)
        byte[] bytes = new byte[8];
        int readLen = 0;//这里表示读取的长度
        FileInputStream fileInputStream = null;//创建空输入流
        try {
            fileInputStream = new FileInputStream(filePath);//创建输入流
            while((readLen = fileInputStream.read(bytes)) != -1){//这里是按数组读取,一个回车直接读了一行
                System.out.println(new String(bytes,0,readLen));
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                fileInputStream.close();//关闭输入流
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

小TIPS:这里的read()方法读取换行符会直接读取为一个空行,readline()方法在包装流bufferreader会用到,届时再详细区分。

  • 字节流输出:FileoutputStream
public void writeFile(){
        String filrepath = "F:\\hello.txt";
        FileOutputStream fileOutputStream = null;
        //创建一个写入对象
        try {
            fileOutputStream = new FileOutputStream(filrepath,true);
            String str = "hsp!world!";
            //也可以定义一个字节数组,提高写入的效果
            byte[] buf = new byte[1024];
            int readLen = 0;
            while ((readLen = fileInputStream.read(buf)) != -1) {
            fileOutputStream.write(buf, 0, readLen);//一定要使用这个方法
            }
            fileOutputStream.write(str.getBytes());//写入一个字符串数组,这里记住必须是字节数组
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                fileOutputStream.close();//关闭字符串流
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

其实就是根据文件路径创建流,然后使用read()和write()方法

  • 字符流输入: FileReader
public void readFile02(){
        String filePath = "F:\\hello.txt";
        FileReader fileReader = null;
        //设置读取的字符
        int readLen = 0;
        char[] chars = new char[9];
        //创建读取对象
        try {
            fileReader = new FileReader(filePath);//原理跟字节流的一模一样!!!
            while((readLen = fileReader.read(chars))!= -1){
                System.out.println(new String(chars,0,readLen));
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                fileReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
  • 字符流输出:FileWriter
public void fileWriter(){
    String filePath = "F:\\hello.txt";
    FileWriter fileWriter = null;
    char[] chars = {'a','b','c'};
        try {
        fileWriter = new FileWriter(filePath);
        fileWriter.write(chars);//默认是覆盖写入,也可以直接用数组写入
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            fileWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
        }

字节流与字符流的区别

1、定义

字节流是一种执行8位字节输入和输出的机制,基本单元为字节;而字符流是Java中执行16位Unicode输入和输出操作的机制,基本单元为Unicode码元

2、结尾

字节流以stream结尾;而字符流以reader和writer结尾

3、处理方式

字节流是最基本的,采用ASCII编码;它通常用于处理二进制数据,它是按字节来处理的,实际上它可以处理任意类型的数据,但它不支持直接写入或读取Unicode码元。

字符流采用Unicode编码,它是按虚拟机的encode来处理,也就是要进行字符集的转化;它通常处理文本数据,它支持写入及读取Unicode码元。

4、缓冲区

字节流默认不使用缓冲区;字符流使用缓冲区

节点流与包装流

在实际应用中,通常使用包装流来对底层的字节流进行包装,比如增加缓冲区,换行读取等方法,提高输入输出的效率。

  1. BufferedReader(在基础字符流上FileReader包装得到)

    public void BufferFile02(){
            String filePath = "F:\\hello.txt";
            FileReader fileReader = null;
            //设置读取的字符
            String line;
            //创建读取对象
            try {
                fileReader = new FileReader(filePath);//原理跟字节流的一模一样!!!
                BufferedReader bos = new BufferedReader(fileReader);//对字节流进行包装
                while((line = bos.readLine())!= null){
                    System.out.println(line);//直接按行读取,极大地提高了读取的效率
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    bos.close();//只需要关闭包装流就好,节点流可以自动关闭
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    
  2. BufferWriter (在基础字符流上FileWriter修饰得到)

    String filePath = "e:\\ok.txt";
    //创建 BufferedWriter
    //说明:
    //1. new FileWriter(filePath, true) 表示以追加的方式写入
    //2. new FileWriter(filePath) , 表示以覆盖的方式写入
    BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath));
    bufferedWriter.write("hello, 韩顺平教育!");//直接写入
    bufferedWriter.newLine();//插入一个和系统相关的换行
    bufferedWriter.write("hello3, 韩顺平教育!");
    bufferedWriter.newLine();
    //说明:关闭外层流即可 , 传入的 new FileWriter(filePath) ,会在底层关闭
    bufferedWriter.close();
    

    ———此外,为了防止每一次输入输出都要从底层调用数据,buffer流设置了缓冲区,这个在网络通讯中起到了很大的作用。

序列化与对象流(包装流的一部分)

​ 由于ObjectOutputStream实现了Serializable,因此常用来进行数据的序列化

String filePath = "e:\\data.dat";
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath));
oos.writeInt(100);// int -> Integer (实现了 Serializable)数据的序列化
oos.writeBoolean(true);// boolean -> Boolean (实现了 Serializable)

转换流(包装流)

相当于writer和reader的子类,可以把字节流转换编码格式,同时转化为字符流。

//2. 指定编码 gbk
InputStreamReader isr = new InputStreamReader(new FileInputStream(filePath), "gbk");
//3. 把 InputStreamReader 传入 BufferedReader
BufferedReader br = new BufferedReader(isr);
br.close();//只需要关闭外层流

close()和flush()的区别

close包含flush功能,但是flush具备刷新完,还可以继续写操作,close执行完了就流关闭了,不能再写入,所以,不能用close来代替flush。

此处贴个链接,学习一下大佬通过动手来分清两者差异的真操作

分清close和flush的区别

Properties

其实就是一个键值对的配置文件

//1. 创建 Properties 对象,读取配置文件
Properties properties = new Properties();
//2. 加载指定配置文件
properties.load(new FileReader("src\\mysql.properties"));
//3. 把 k-v 显示控制台
properties.list(System.out);
//4. 根据 key 获取对应的值
String user = properties.getProperty("user");
String pwd = properties.getProperty("pwd");
System.out.println("用户名=" + user);
System.out.println("密码是=" + pwd);

网络通讯中IO流的应用

服务器端与客户端的数据传输:

这里就是用了包装流对于基本的输入输出流进行包装

 //服务器端代码:接受并输出
//创建一个serverSocket对象,在本机的8888端口监听(serverSocket相当于一个服务)
        ServerSocket serverSocket = new ServerSocket(8888);
        //返回客户端连接的对象(找到socket)
        Socket socket = serverSocket.accept();
        //将客户端写入数据通道的数据接口,或者socket接口的输入流
        InputStream ios = socket.getInputStream();
        //将基础字节流转换为字符流(涉及到两个包装流)
        BufferedReader bos = new BufferedReader(new InputStreamReader(ios));

        //服务器端的处理逻辑
        String s = bos.readLine();//直接来读取方法
        String answer = "";
        if("name".equals(s)){
            answer = "我是本机";
        }else if("hobby".equals(s)){
            answer = "编写计算机程序";
        }else{
            answer = "我听不懂你说的话";
        }

        //5. 获取socket相关联的输出流(因为默认是字节传输的方式,所以需要努努力改成字符传输的方式)
        OutputStream outputStream = socket.getOutputStream();
        //    使用字符输出流的方式回复信息
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
        bufferedWriter.write(answer);
        bufferedWriter.newLine();// 插入一个换行符,表示回复内容的结束
        bufferedWriter.flush();//清空缓冲区数据,但是不关闭流

        //关闭外层流
        bos.close();
        bufferedWriter.close();
        //关闭网络服务
        socket.close();
        serverSocket.close();
 //客户端代码
//连接到服务端的8888接口,产生socket对象
        Socket socket = new Socket(InetAddress.getLocalHost(),8888);
        OutputStream outputStream = socket.getOutputStream();
        BufferedWriter bof = new BufferedWriter(new OutputStreamWriter(outputStream));//转化为字符流

        //从键盘读取用户问题
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入你的问题:");
        String question = scanner.next();

        bof.write(question);
        bof.newLine();
        bof.flush();//字符流必须得手动刷新一下才能写入数据通道(不然的话容易缓冲区堵塞)

        //4. 获取和socket关联的输入流. 读取数据(字符),并显示
        InputStream inputStream = socket.getInputStream();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String s = bufferedReader.readLine();
        System.out.println(s);

        //关闭外层流和对象
        bof.close();
        bufferedReader.close();
        socket.close();
        System.out.println("客户端退出!");
posted @   深海之燃  阅读(44)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示