Java IO

IO

IO 即 Input 和 Output,输入和输出。

  • 输入:将数据输入到计算机内存的过程;
  • 输出:将数据输出到外部存储(例如文件)的过程;

对于 IO 也就是我们通常说的 IO 流,在 Java 中分为输入流和输出流,按处理的数据单位又分为字节流和字符流

字节流与字符流:

  • 字节流和字符流的用法几乎完全一样,区别在于它们操作的数据单位不同。字节流操作的是字节,字符流操作的是字符;
  • 一般音频文件、图片等媒体文件用字节流比较好,如果涉及到字符的话使用字符流比较好;
  • 字符流默认采用的是 Unicode 字符集。

Unicode 字符集:
百科:Unicode 是国际标准字符集,它将世界各种语言的每个字符定义一个唯一的编码,以满足跨语言、跨平台的文本信息转换
简言之:Unicode 是字符集,是很多个字符的集合,它规定了统一的字符编码标准(即每个字符的二进制),而 UTF-8、UTF-16、UTF-32 才是真正的字符编码规则,也可以理解为是其具体的实现。
目前的文字编码标准有 ASCII、GBK、Unicode等

Java IO 流的类都是从以下4个父类(抽象类)中派生而来的:

  • InputStream/Reader:所有输入类的父类,前者是字节输入流,后者是字符输入流
  • OutputStream/Writer:所有输出类的父类,前面是字节输出流,后者是字符输出流

下面就来通过例子来具体说明一下 Java IO 流。

字节流

字节输入流(InputStream)

InputStream 用于从数据源(通常是文件)读取数据(字节数据)到内存中。java.io.InputStream 抽象类是所有字节输入流的父类。

常用方法:

  • read():返回输入流中下一个字节的数据。返回的值介于 0 到 255 之间。如果未读取任何字节,则代码返回 -1 ,表示文件结束;
  • read(byte b[ ]) : 从输入流中读取一些字节存储到数组 b 中。如果数组 b 的长度为零,则不读取。如果没有可用字节读取,返回 -1。如果有可用字节读取,则最多读取的字节数最多等于 b.length , 返回读取的字节数。这个方法等价于 read(b, 0, b.length);
  • skip(long n):忽略输入流中的 n 个字节 ,返回实际忽略的字节数;
  • available():返回输入流中可以读取的字节数;
  • close():关闭输入流释放相关的系统资源
  1. 使用 FileInputStream 读取数据。该对象是一个比较常用的字节输入流对象,可以直接在对象实例化时指定要读取的文件路径,它可以读取单字节数据(使用 read() 方法),也可以将字节数据读取到字节数组中.

案例一:将名为 test1.txt 的文件中的内容读取出来。
实现代码如下:

public class InputTest {
    /*
    * 对 FileInputStream 进行举例
    * */
    public static void FileInputStreamTest(){  // 此处使用静态方法,方便后续不使用类对象进行调用
        try {
            FileInputStream fileInputStream = new FileInputStream("test1.txt");  // 从指定文件中读取字节流,并输入到内存中   注意此处文件的位置,是当前目录下,即和项目是在同一级目录中
            int result = 0; // 定义一个变量,用来记录文件中字节数据
            while ((result = fileInputStream.read() ) != -1 ){  // 此处 read() 方法一次只能读一个字节的数据,所以采用 while 循环读取文件中的所有数据
                System.out.print((char) result); // 因为 read 方法读出来的返回值介于 0 到 255 之间,所以要将 result 强转成 char 类型的数据,才可以显示的看到文件中的内容
            }
			// 关闭流
            fileInputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }


    public static void main(String[] args) {
        FileInputStreamTest();

    }

}

文件位置以及文件内容:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
这样就将指定文件中的内容读取出来了。

  1. 我们通常使用 BufferedInputStream (字节缓冲输入流) 与 FileInputStream 组合进行使用。
    缓冲字节流是为高效率而设计的,真正的读写操作还是靠FileOutputStream和FileInputStream

案例二:使用 BufferedInputStream 和 FileInputStream 读取文件中的数据。

public class InputTest {

    /*
    * FileInputStream 与 BufferedInputStream 组合使用
    * */
    public static void FileAndBufferedInputStream(){
        try {
            BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("test1.txt"));
            int result = 0;
            while ((result = bufferedInputStream.read()) != -1){
                System.out.print((char)result);
            }
            bufferedInputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        FileAndBufferedInputStream();
    }

}

结果是一样的:
在这里插入图片描述

  1. DataInputStream 用于读取指定类型数据,不可以单独使用,必须结合其它流进行使用
    public  void DataInputTest(){
        try {
            FileInputStream fileInputStream = new FileInputStream("test1.txt");
            DataInputStream dataInputStream = new DataInputStream(fileInputStream);
            //dataInputStream.readBoolean(); // 从输入流中读取一个 Boolean 值
            dataInputStream.readInt();  // 从输入流中读取一个整数
            //dataInputStream.readChar(); // 从输入流中读取一个字符    等等还有好多方法
            dataInputStream.close();
            fileInputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  1. ObjectInputStream 从输入流中读取 Java 对象。该对象常用于反序列化,即将一个字节数组转换成一个对象

案例三:将传过来的字节数组转换成一个对象(反序列化)

// 把一个字节数组反序列化成一个对象
    public static Object toObject(byte[] data) throws IOException, ClassNotFoundException {
    	// 用 object 来存放反序列化后的对象
        Object object = null;
        try(ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data)) { // 将 data 放到 byteArrayInputStream 流中(即放到变长的字节数组中),然后让 objectInputStream 从该字符数组中反序列化成对象
            try(ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream)) {
            	//此处的 readObject, 就是从 data 这个 byte[] 中读取数据并进行反序列化
                object = objectInputStream.readObject();
            }
        }
        return object;
    }

补充:

  • 此处使用 try(){} 这样的语句是因为这样写系统会自动关闭流对象,而不需要我们手动进行关闭;
  • 用于序列化和反序列化的类必须实现 Serializable 接口,对象中如果有属性不想被序列化,使用 transient 修饰。

字节输出流(OutputStream)

OutputStream 用于将字节数据写入到指定地方(一般为文件中)。java.io.OutputStream 抽象类是所有字节输出流的父类。

快速记忆:
字节输入流:数据源(文件)——> 内存
字节输出流:字节数据(内存)——> 文件

常用方法:

  • write(int b):将特定字节写入输出流;
  • write(byte b[ ]) : 将数组b 写入到输出流,等价于 write(b, 0, b.length);
  • flush():刷新此输出流并强制写出所有缓冲的输出字节;
  • close():关闭输出流释放相关的系统资源
  1. FileOutputStream:最常用的字节输出流对象,与 FileInputStream 类似,可以输出单字节数据,也可以输出指定的字节数组。
    案例四:将字节数据写到 output.txt 文件中。
public class OutputStream {
    public static void main(String[] args) {
        try(FileOutputStream fileOutputStream = new FileOutputStream("output.txt")){
            byte[] arr = "output".getBytes();  // 将 output 转化为字节
            fileOutputStream.write(arr); // 将 output 放到 output.txt 文件中
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

输出结果:
在这里插入图片描述
此处若没有创建 output.txt 文件,执行程序后该文件会自动创建。

  1. BufferedOutputStream:字节缓冲输出流,与 BufferedInputStream 类似,通常和 FileOutputStream 配合使用。

案例五:将字节数据写到 output2.txt 文件中。

    public static void main(String[] args) {
        try(BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("output2.txt"))){
            byte[] arr = "output2".getBytes();  // 将 output 转化为字节
            bufferedOutputStream.write(arr);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

若没有指定文件会自动创建。
在这里插入图片描述

  1. DataOutputStream:用于写入指定类型数据,不能单独使用,须与其它流结合使用。
    案例六:将指定类型的数据(例如字节型,Boolean型,int型等) 写入 output3.txt 文件中。
    public static void main(String[] args) {
        try(FileOutputStream fileOutputStream = new FileOutputStream("output3.txt")){
            try(DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream)){
                //dataOutputStream.writeBoolean(true);  // Boolean 类型和 int 类型在 txt 文件中是看不到(乱码)的
                //dataOutputStream.writeInt(888);
                dataOutputStream.writeBytes("output3"); // 此处向文件中写入二进制字符串
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

在这里插入图片描述

  1. ObjectOutputStream:用于将对象写入到输出流。常用于序列化(即把一个对象转化成一个字节数组)
    案例七: 将对象序列化成一个数组、
    public static byte[] toBytes(Object object) throws IOException {  // 此处注意使用 try(){}这样写的原因是:这样可以不用手动关闭流对象
        try(ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()){  //这个流对象相当于一个变长的字节数组.
                                                                              // 就可以把 Object 序列化的数据给逐渐的写入到 byteArrayOutputStream 中,再统一转成 byte[]
            try(ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream)){
                //此处 writeObject 就会把该对象进行序列化,生成二进制字节数据,就会写入到 objectOutputStream 中
                //由于 objectOutputStream 又关联了 ByteArrayOutputStream, 则最终结果就会写入到 byteArrayOutputStream 中
                objectOutputStream.writeObject(object);
            }
            // 将byteArrayOutputStream 中持有的二进制数据取出来,转成 byte[]
            return byteArrayOutputStream.toByteArray();
        }
    }

序列化和反序列化:

  1. 序列化:对象 ——> 字节数组;使用 ObjectOutputStream 对象 ,结合 ByteArrayOutputStream 对象;
  2. 反序列化:字节数组 ——> 对象;使用 ObjectInputStream 对象,结合 ByteArrayInputStream 对象;

字符流

是 IO 流提供的一个可以直接操作字符的接口,方便对字符进行流操作。字符流默认采用的是 Unicode 编码,也可以通过构造方法来自己定义编码规则。

字符输入流(Reader)

Reader 用于从数据源头(一般是文件) 读取字符数据到内存中,java.io.Reader 抽象类是所有字符输入流的父类。

常用方法:

  • read():从输入流读取一个字符;如果未读取任何字符,则代码返回 -1 ,表示文件结束
  • read(char[] a) : 从输入流中读取一些字符,并将它们存储到字符数组 a中,等价于 read(a, 0, a.length);
  • skip(long n):忽略输入流中的 n 个字符,返回实际忽略的字符数;
  • close():关闭输入流并释放相关的系统资源。
  1. InputStreamReader:是字符输入流转换为字节的桥梁,其子类 FileReader 是基于该基础上的封装,可以直接操作字符文件
    案例一:对 reader 文件中的字符内容进行操作。
public static void main(String[] args) {
        try(FileReader fileReader = new FileReader("reader.txt")){
            int content = 0;
            long skip = fileReader.skip(2);
            System.out.println("实际忽略的字符数为:" + skip);
            System.out.print("从字符文件读取到的内容为:" );
            while ((content = fileReader.read()) != -1){
                System.out.print((char) content);  // 强转为字符类型,方便观察输出结果
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  1. BufferedReader:字符缓冲输入流,常与 FileReader 搭配进行使用。
    案例二:读取 reader.txt 文件中的内容
public static void main(String[] args) {
        try(BufferedReader bufferedReader = new BufferedReader(new FileReader("reader.txt"))){
            int content = 0;
            System.out.print("从字符文件读取到的内容为: ");
            while ((content = bufferedReader.read()) != -1){
                System.out.print((char) content);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

在这里插入图片描述

字符输出流(Writer)

Writer 用于将字符数据写入到指定地方(通常是文件),java.io.Writer 抽象类是所有字符输出流的父类。

常用方法:

  • write(int c) : 写入单个字符;
  • write(char[] a):写入字符数组 a,等价于write(a, 0, a.length);
  • write(String str):写入字符串;
  • append(char c):将指定的字符附加到指定的 Writer 对象并返回该 Writer 对象;
  • flush():刷新此输出流并强制写出所有缓冲的输出字符;
  • close():关闭输入流并释放相关的系统资源。
  1. OutputStreamWriter:是字符流转换为字节流的桥梁,其子类 FileWriter 是基于该基础上的封装,可以直接将字符写入到文件。
    案例三:将 我也喜欢你!!! 写到 result.txt 文件中。
public static void main(String[] args) {
        try(FileWriter fileWriter = new FileWriter("result.txt")){
            fileWriter.write("我也喜欢你!!!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

在这里插入图片描述
若没有手动创建文件,程序启动后会自动创建文件。

  1. 字符缓冲输出流:BufferedWriter,通常与 FileWriter 配合使用。
    案例四:将 有为青年 写入到 result2.txt 文件中:
public static void main(String[] args) {
        try(BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("result2.txt"))){
            bufferedWriter.write("有为青年");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

在这里插入图片描述

缓冲流

作用:IO 操作是很消耗性能的,缓冲流将数据加载至缓冲区,一次性读取/写入多个字节/字符,从而避免频繁的 IO 操作,提高流的传输效率
缓冲区:内部都维护了一个数组作为缓冲区。
用法:

// 搭配使用
// 字节缓冲输入流:
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("input.txt"));
// 字节缓冲输出流:
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("output2.txt"))

缓冲流分为字节缓冲流和字符缓冲流,它们都是相似的。

  1. 字节缓冲流:
    • 字节缓冲输入流:BufferedInputStream,从数据源(通常是文件)读取数据(字节数据)到内存的过程中不会一个字节一个字节的读取,而是会先将读取到的字节存放在缓存区,并从内部缓冲区中单独读取字节。这样大幅减少了 IO 次数,提高了读取效率。
    • 字节缓冲输出流:BufferedOutputStream,将字节数据写入到指定地方 (通常是文件) 的过程中不会一个字节一个字节的写入,而是会先将要写入的字节存放在缓存区,并从内部缓冲区中单独写入字节
  2. 字符缓冲流:
    • 字符缓冲输入流(BufferedReader):从数据源(通常是文件)读取数据(字符数据)到内存的过程中不会一个字符一个字符的读取,而是会先将读取到的字符存放在缓存区,并从内部缓冲区中单独读取字符
    • 字符缓冲输出流(BufferedWriter):与 BufferOutputStream 是类似的,只是它操作的是字符。
  • 13
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值