学习日记(IO 流详细内容上篇)

学习日记(IO 流详细内容上篇)

一、IO 流概述

IO 流也成为输入、输出流,是用来读写数据的。

  • I 表示 input,是数据从硬盘文件读入到内存的过程,称之为输入,负责读;
  • O 表示 output,是内存程序中的数据从内存写出到磁盘文件的过程,称之为输出,负责写。

流的分类:字节输入流、字节输出流、字符输入流、字符输出流。

  • 字节输入流:磁盘文件/网络中的数据(以字节的方式)—>(读入到)内存;
  • 字节输出流:内存中的数据(以字节的方式)—>(写入到)磁盘文件/网络;
  • 字符输入流:磁盘文件/网络中的数据(以字符的方式)—>(读入到)内存;
  • 字符输出流:内存中的数据(以字符的方式)—>(写入到)磁盘文件/网络;

其中,字节流可以读写任何文件,但更适合读写音视频文件;字符流更适合读写文本文件。


二、文件字节输入流(FileInputStream)

读取文件内容的步骤

  • 创建一个文件字节输入流管道与源文件接通,如:InputStream is = new FileInputStream("基础语法\\src\\data.txt");
  • 调用方法读取字节。

1. 每次读取一个字节

方法名说明
public abstract int read() throws IOException每次读取一个字节返回,返回值类型为 int,如果字节已经读完,则返回 -1

注意:因为 read 方法的返回值为字节,要想看到对应的字符,需要强制类型转化。

存在的问题:性能较慢;读取中文字符输出无法避免乱码问题(因为每次读取只能是一个字节,而中文字符一般用两个或三个字节表示)。

2. 每次读取一个字节数组

方法名说明
public int read(byte b[]) throws IOException每次读取一个字节数组返回,返回值类型为 int,如果字节已经读完,则返回 -1

注意:read 方法返回 int 类型的值为每次读取的字节个数,而字节数组中存放着每个读取的字节;第三个参数 len 表示长度。

存在的问题:读取的性能得到了提升,但读取中文字符输出无法避免乱码问题。

3. 一次读完全部字节

  • 方案一:定义一个和文件大小一样大的字节数组,然后用读取字节数组的方法,一次性读取完成。

  • 方案二:用 readAllBytes 方法直接把文件的全部数据读取到一个字节数组中,如:byte[] buffer = is.readAllBytes();,然后将字节数组解码为字符,注意:该方法从 JDK 9 开始。

总结:一次性读完全部字节可以保证字节输入流读取中文内容输出不乱码,如果文件过大,定义的字节数组可能引起内存溢出。


三、文件字节输出流(FileOutputStream)

写字节数据到文件的步骤

  • 创建一个文件字节输出流管道与目标文件接通,如:OutputStream os = new FileOutputStream("基础语法\\src\\data2.txt");
  • 调用方法写入数据。

分为三种:写一个字节进去、写一个字节数组进去、写一个字节数组的一部分进去。

方法名说明
public abstract void write(int b) throws IOException一个字节进去
public void write(byte b[]) throws IOException一个字节数组进去
public void write(byte b[], int off, int len) throws IOException一个字节数组的一部分进去

注意:在第三个方法中,第二个参数是起始位置(索引,从 0 开始),第三个参数是长度,表示要写几个字节。

补充知识

  • 若要输出换行,则:os.write("\r\n".getBytes());
  • 创建一个文件字节输出流管道与目标文件接通时,如果文件不存在,会自动创建文件,注意加上文件的后缀名。
  • OutputStream os = new FileOutputStream("基础语法\\src\\data2.txt"); 表示每次写的时候都会先清空之前的数据,然后再写入数据。若想在原先的数据中继续写入数据,则应该追加管道,即增加一个参数,如:OutputStream os = new FileOutputStream("基础语法\\src\\data2.txt", true);
  • 如果要写入中文字符,不能用”写入一个字节“这种方法,而应该用”写入字节数组“这种方法,先用 getBytes 方法将字符串变为字节数组,再写入。
  • 在全部写完数据后,要用 os.flush();os.close();刷新数据关闭流(释放资源,关闭流包括了刷新数据)。
  • 刷新数据后可以继续使用流,关闭流后不能再使用流。


四、文件拷贝

支持一切文件的复制,因为所有的文件都是由字节组成的,只要前后文件格式编码一致就没有问题。

  • 对于小文件的拷贝,直接一次读完全部字节。

需求:把 data3 文件(156 字节)拷贝到 E:\桌面\一些文件 中。

  • 对于大文件的拷贝,用每次读取一个字节数组的方法(常用)。

需求:将 E:\Do.docx 文件(226 KB,232,087 字节)拷贝到 E:\桌面\一些文件 下。


五、释放资源的两种方式

  • try - catch - finally
  • try - with - resource

1. try - catch - finally

特点:被 finally 控制的语句最后一定会执行,除非 JVM 退出。

作用:finally 代码块是最终一定要执行的,可以在代码执行完毕的最后用于释放资源。

2. try - with - resource

资源对象:实现了 Closeable/AutoCloseable 接口的类对象。

特点和作用:自动释放资源、代码简洁。

package com.residue.IOstream;

import java.io.*;

public class CopyDemo02 {

    public static void main(String[] args) {

        //需求:将 E:\Do.docx 文件拷贝到 E:\桌面\一些文件 下

        try (
                InputStream is = new FileInputStream("E:\\Do.docx");
                OutputStream os = new FileOutputStream("E:\\桌面\\一些文件\\Do.docx");
                ) {

            byte[] buffer = new byte[1024];
            int len;
            while ((len = is.read(buffer)) != -1) {
                os.write(buffer, 0, len);    //写一个字节数组
                os.flush();

            }

        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

六、文件字符输入流(FileReader)

读取文件内容的步骤

  • 创建一个字符输入流管道与源文件接通,如:Reader fr = new FileReader("基础语法\\src\\data3.txt");
  • 调用方法读取字符。

1. 每次读取一个字符

方法名说明
public int read() throws IOException每次读取一个字符返回,返回值类型为 int,如果字符已经读完,则返回 -1

注意:因为 read 方法的返回值为字符的编号,要想看到对应的字符,需要强制类型转化。

字符流的好处:如果代码和文件编码一致,读取中文字符不会出现乱码。

问题:性能较慢。

2. 每次读取一个字符数组

方法名说明
public int read(char cbuf[]) throws IOException每次读取一个字符数组返回,返回值类型为 int,如果字符已经读完,则返回 -1

注意:read 方法返回 int 类型的值为每次读取的字符个数,而字符数组中存放着每个读取的字符;第三个参数 len 表示长度。

每次读取一个字符数组的优势:读取的性能得到了提升。


七、文件字符输出流(FileWriter)

写字符数据到文件的步骤

  • 创建一个文件字符输出流管道与目标文件接通,如:Writer fw = new FileWriter("基础语法\\src\\data5.txt");
  • 调用方法写入数据。

分为五种:写一个字符进去、写一个字符串进去、写一个字符数组进去、写一个字符串的一部分进去、写一个字符数组的一部分进去。

方法名说明
public void write(int c) throws IOException一个字符进去
public void write(String str) throws IOException一个字符串进去
public void write(char cbuf[]) throws IOException一个字符数组进去
public void write(String str, int off, int len) throws IOException一个字符串的一部分进去
public void write(char cbuf[], int off, int len) throws IOException一个字符数组的一部分进去

注意:其他注意点和文件字节输出流的注意点相同。


八、总结

字节流和字符流如何选择使用:

  • 字节流适合做一切文件的拷贝,如音视频、文本等;
  • 字节流不适合读取中文内容输出
  • 字符流适合做文本文件的操作,如读、写。

注意:

  1. 读的时候同时只能有一个 read,否则读的内容错误。

  1. 文件字节输入流中,每次读取一个字节,返回值为 int,表示字节的大小;每次读取一个字节数组,返回值也为 int,但是表示每次读取的字节个数。

  2. 需要加 if 语句判断流是否为 null,否则,如果在流产生前就出现异常,会报空指针异常。

  1. 不建议 finally 中加 return 语句。

  1. 资源对象是指实现了 Closeable/AutoCloseable 接口的类对象。

  1. 字符和对应的字节(编号)相互转换用类型转换

  1. 将字符串变为字符数组:调用 toCharArray 方法,如:char[] chars = "你好啊帅哥!".toCharArray();
  2. 将字符串变为字节数组:调用 getBytes 方法,如:byte[] bytes = "今天星期四".getBytes();
  3. 将字节数组或字符数组变为字符串:使用 String 的构造器。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Sun 3285

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值