Java|Java 学习笔记(十一)IO 流

IO 流是有起点和终点的有序的字节序列
IO 流的分类

  • 输入流和输出流
    程序从外面读数据就是输入流,程序把数据保存到外面就是输出流
  • 字节流和字符流
    以字节为单位处理流中的数据就是字节流,以字符为单位处理流中的数据就是字符流
  • 节点流和处理流
    直接从设备读写数据就是节点流,处理流是对节点流的包装
FileInputStreamFileOutputStream FileInputStream 流以字节为单位读取文件中的内容,FileOutputStream 流以字节为单位把数据保存到文件中。这一对流类可以读写所有格式的文件
import java.io.FileInputStream; import java.io.IOException; /** * FileInputStream 流的基本使用 */ public class Test01 { public static void main(String[] args) throws IOException { // 通过 FileInputStream 的构造方法指定要读取的文件,文件内容:abcdef FileInputStream fis = new FileInputStream("/Users/Desktop/test"); // 调用 available() 方法可以返回还有多少个字节未读 System.out.println(fis.available()); // 调用 read() 方法可以从文件中读取一个字节 int bb = fis.read(); System.out.println(bb); // 调用 skip() 方法可以跳过指定的字节数 // 跳过2字节 fis.skip(2); System.out.println(fis.available()); System.out.println(fis.read()); // 关闭流 fis.close(); } }

输出内容:
6 97 3 100

import java.io.FileInputStream; import java.io.IOException; /** * 使用 FileInputStream 流读取文件的所有字节 */ public class Test02 { public static void main(String[] args) throws IOException { // 通过构造方法指定要读取的文件 FileInputStream fis = new FileInputStream("/Users/Desktop/test"); // 调用 read() 方法读取一个字节,如果读到文件末尾会返回 -1 int bb = fis.read(); while (bb != -1) { System.out.println((char)bb); bb = fis.read(); }// 关闭流 fis.close(); } }

输出内容:
a b c d e f

import java.io.FileInputStream; import java.io.IOException; import java.util.Arrays; /** * 使用 FileInputStream 流读取文件的字节,把读取到的字节保存到字节数组中 */ public class Test03 { public static void main(String[] args) throws IOException { // 通过构造方法指定要读取的文件,文件内容:abcdef FileInputStream fis = new FileInputStream("/Users/Desktop/test"); // 调用 read(byte[] b) 方法读取若干字节存储到 bytes 数组中,返回读到的字节数 byte [] bytes = new byte[4]; int len = fis.read(bytes); // 读取到4个字节 System.out.println(len); // 输出结果:[97, 98, 99, 100] System.out.println(Arrays.toString(bytes)); // 再继续读取文件 len = fis.read(bytes); // 读取到2个字节 System.out.println(len); // 输出结果:[101, 102, 99, 100] System.out.println(Arrays.toString(bytes)); // 再继续读取文件 len = fis.read(bytes); // 已经读到文件末尾,返回 -1 System.out.println(len); // 输出结果:[101, 102, 99, 100] System.out.println(Arrays.toString(bytes)); // 关闭流 fis.close(); } }

import java.io.FileOutputStream; import java.io.IOException; /** * FileOutPutStream 流以字节为单位把数据保存到文件中 */ public class Test04 { public static void main(String[] args) throws IOException { // 调用构造方法指定要写入的文件,如果文件不存则会创建该文件 // 以覆盖的形式写入文件 //FileOutputStream fos = new FileOutputStream("/Users/Desktop/test"); // 以追加的形式写入文件 FileOutputStream fos = new FileOutputStream("/Users/Desktop/test", true); // 调用 write(int) 方法,一次写入一个字节 fos.write(97); fos.write(98); fos.write(99); // 调用 write(byte[] b) 方法,把一个字节数组的所有字节写入文件 byte [] bytes = "hello FileOutPutStream".getBytes(); fos.write(bytes); // 调用 write(byte[] b, int off, int len) 方法,把一个字节的部分字节写入文件 fos.write(bytes, 0, 5); // 关闭流 fos.close(); } }

文件内容:
abchello FileOutPutStreamhello

BufferedInputStreamBufferedOutputStream BufferedInputStream 缓冲输入字节流,字节流有一个8192字节的数组作为缓冲区,程序从缓冲区读取数据,不直接操作文件
BufferedOutputStream 缓冲输出字节流,程序把数据写入缓冲区,再由其他字节流从缓冲区把数据写入文件
BufferedInputStreamBufferedOutputStream 属于处理流
import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.IOException; /** * BufferedInputStream 流读取文件 */ public class Test01 { public static void main(String[] args) throws IOException { m1(); }public static void m1 () throws IOException { // 先创建字节流,文件内容:hello FileInputStream fis = new FileInputStream("/Users/Desktop/test"); // 再创建缓冲流对字节流进行缓冲 BufferedInputStream bis = new BufferedInputStream(fis); // 从缓冲区中读取文件 int bb = bis.read(); while (bb != -1) { System.out.println((char)bb); bb = bis.read(); }// 关闭缓冲流 bis.close(); } }

输出结果:
h e l l o

import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.io.IOException; /** * BufferedOutputStream 流写入文件 */ public class Test02 { public static void main(String[] args) throws IOException { m2(); }public static void m2 () throws IOException { // 先创建字节流 FileOutputStream fos = new FileOutputStream("/Users/Desktop/test"); // 再创建缓冲流 BufferedOutputStream bos = new BufferedOutputStream(fos); // 把数据写入缓冲区 bos.write(65); bos.write(66); bos.write(67); // 刷新缓冲区,把数据从缓冲区写入文件 bos.flush(); // 关闭缓冲流,直接关闭也会刷新缓冲区 bos.close(); } }

文件内容:
ABC

DataInputStreamDataOutputStream 之前的 FileInputStream 流从文件中读取一组 01 二进制序列,在转换成相对应的数据,FileOutputStream 把相对应的数据转换成 01 二进制序列,再写入文件
DataInputStream 流可以直接中文件中读取整数,小数,字符,字符串,布尔类型类型的数据,DataOutputStream 可以直接把整数,小数,字符,字符串,布尔类型的数据写入文件
import java.io.DataOutputStream; import java.io.FileOutputStream; import java.io.IOException; /** * DataOutputStream 流把带有格式的数据写入文件 */ public class Test01 { public static void main(String[] args) throws IOException { // 先创建字节流 FileOutputStream fos = new FileOutputStream("/Users/Desktop/test"); // 在创建 DataOutputStream 流 DataOutputStream dos = new DataOutputStream(fos); // 写入文件,写入的数据直接读入会显示乱码,需要使用 DataInputStream 流来读取 dos.writeInt(123); dos.writeDouble(3.14); dos.writeChar('汉'); dos.writeBoolean(false); dos.writeUTF("hello"); // 关闭流 dos.close(); } }

import java.io.DataInputStream; import java.io.FileInputStream; import java.io.IOException; /** * DataInputStream 读取数据 */ public class Test02 { public static void main(String[] args) throws IOException { // 先创建字节流 FileInputStream fis = new FileInputStream("/Users/Desktop/test"); // 再创建 DataInputStream 流 DataInputStream dis = new DataInputStream(fis); // 读取的顺序与写入的顺序需要保持一致 int i = dis.readInt(); double d = dis.readDouble(); char c = dis.readChar(); boolean b = dis.readBoolean(); String s = dis.readUTF(); // 关闭流 dis.close(); // 输出 System.out.println(i); System.out.println(d); System.out.println(c); System.out.println(b); System.out.println(s); } }

输出内容:
123 3.14 汉 false hello

ObjectInputStreamObjectOutputStream ObjectOutputStream 流把对象转换为二进制序列写入到文件,称为对象序列化
ObjectInputStream 流把读取到的二进制序列转换为对象,称为对象反序列化
对象序列化与反序列化的前提是对象的类要实现 Serializable 接口,这个接口是一个标志接口,没有抽象方法
import java.io.Serializable; /** * 定义一个类 */ public class Person implements Serializable { String name; int age; public Person(String name, int age) { this.name = name; this.age = age; }@Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } }

import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; /** * ObjectOutputStream 流把对象写入文件 */ public class Test01 { public static void main(String[] args) throws IOException { Person p = new Person("张三", 18); // 创建字节流 FileOutputStream fos = new FileOutputStream("/Users/Desktop/test"); // 创建 ObjectOutputStream 流 ObjectOutputStream oos = new ObjectOutputStream(fos); // 把对象写入文件,写入文件之后,需要使用 ObjectInputStream 流读取 oos.writeObject(p); // 关闭流 oos.close(); } }

import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; /** * ObjectInputStream 流读取对象 */ public class Test02 { public static void main(String[] args) throws IOException, ClassNotFoundException { // 创建字节流 FileInputStream fis = new FileInputStream("/Users/Desktop/test"); // 创建 ObjectInputStream 流 ObjectInputStream ois = new ObjectInputStream(fis); // 读取对象 Object o = ois.readObject(); // 关闭流 ois.close(); // 输出 System.out.println(o); } }

输出内容:
Person{name='张三', age=18}

PrintStream 打印内容到文件
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.PrintStream; /** * PrintStream 打印字节流 */ public class Test01 { public static void main(String[] args) throws FileNotFoundException { // 创建字节流 FileOutputStream fos = new FileOutputStream("/Users/Desktop/test"); // 创建打印流 PrintStream ps = new PrintStream(fos); // 打印字节流常用的方法,print() 和 println(),打印信息到文件中 ps.print("打印完不换行"); ps.println("打印完换行"); // 设置 system.out.println 方法,通过打印流打印到文件中 System.setOut(ps); System.out.println("现在打印的内容不显示在屏幕上,而是打印到 test 文件中"); // 把异常信息打印到文件中 try { FileInputStream fis = new FileInputStream("不存在的文件"); }catch (FileNotFoundException e) { // 把异常信息打印到 test 文件中 e.printStackTrace(ps); }// 关闭流 ps.close(); } }

文件内容:
打印完不换行打印完换行 现在打印的内容不显示在屏幕上,而是打印到 test 文件中 java.io.FileNotFoundException: 不存在的文件 (No such file or directory) at java.base/java.io.FileInputStream.open0(Native Method) at java.base/java.io.FileInputStream.open(FileInputStream.java:219) at java.base/java.io.FileInputStream.(FileInputStream.java:157) at java.base/java.io.FileInputStream.(FileInputStream.java:112) at printio.Test01.main(Test01.java:28)

FileReaderFileWriter IO 流类中以 Reader 和 Writer 结尾的是字符流,用于读写只有字符的纯文本文件
FileReaderFileWriter 只能读写与当前环境编码兼容的文件
import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; /** * FileReader 和 FileWriter */ public class Test01 { public static void main(String[] args) throws IOException { readChar(); readChar2(); writeChar(); }// 读取字符文件 public static void readChar () throws IOException { // 创建字符流 FileReader fr = new FileReader("/Users/Desktop/test"); // 调用 read() 方法读取一个字符,返回读到的字符的码值,如果读到末尾返回 -1 int code = fr.read(); while (code != -1) { System.out.print((char)code); code = fr.read(); } // 关闭流 fr.close(); }// 读取若干字符保存到字符数组 public static void readChar2 () throws IOException { // 创建字符流 FileReader fr = new FileReader("/Users/Desktop/test"); // 定义一个数组 char [] chars = new char[1024]; // 读取若干字符存储到字符数组 chars 中,返回读到的字节数 int len = fr.read(chars); while (len != -1) { System.out.print(String.valueOf(chars, 0, len)); len = fr.read(chars); } // 关闭流 fr.close(); }// 写入字符文件 public static void writeChar () throws IOException { // 创建字符流 FileWriter fw = new FileWriter("/Users/Desktop/test"); // 写入字符文件 // 一次写入一个字符 fw.write('1'); fw.write('a'); fw.write('汉'); fw.write('#'); // 写入字符数组 char [] chars = "hello charArray".toCharArray(); fw.write(chars); // 写入字符串 fw.write("hello str")// 关闭流 fw.close(); } }

InputStreamReaderOutputStreamWriter 如果想要读写编码不一致的文本文件,可以使用 InputStreamReaderOutputStreamWriter
InputStreamReader 可以把字节流转换为字符流
OutputStreamWriter 可以把字符流转换为字节流
import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.IOException; /** * InputStreamReader 和 OutputStreamWriter */ public class Test02 { public static void main(String[] args) throws IOException { readGBKFile(); writeGBKFile(); }// 在 UTF8 环境读取 GBK 文件 public static void readGBKFile () throws IOException { // 创建字节流 FileInputStream fis = new FileInputStream("/Users/Desktop/test"); // 创建转换流,把字节流以 GBK 格式转换为字符流 InputStreamReader isr = new InputStreamReader(fis, "GBK"); // 读取文件内容,返回的是字符对应的码值 int code = isr.read(); while (code != -1) { System.out.print((char)code); code = isr.read(); } // 关闭流 isr.close(); }// 在 UTF8 环境下写入 GBK 文件 public static void writeGBKFile () throws IOException { // 创建字节流 FileOutputStream fos = new FileOutputStream("/Users/Desktop/test"); // 创建转换流,把字符流以 GBK 格式转换为字节流 OutputStreamWriter osw = new OutputStreamWriter(fos); // 写入文件 osw.write("当前是 UTF8 编码环境,写入文件的编码是 GBK"); // 关闭流 osw.close(); } }

BufferedReaderBufferedWriter BufferedWriter 可以对输出字符流进行缓冲,写入数据到缓冲区,刷新缓冲区,或者缓冲区已满,或者关闭流时,将缓冲区的数据写入文件
BufferedReader 可以对输入字符流进行缓冲,从缓冲区读取数据,不直接操作文件
import java.io.IOException; import java.io.FileWriter; import java.io.FileReader; import java.io.BufferedWriter; import java.io.BufferedReader; /** * BufferedReader 和 BufferedWriter */ public class Test03 { public static void main(String[] args) throws IOException { writerBf(); readBf(); }// 使用字符缓冲流写入文件 public static void writerBf () throws IOException { // 创建字符流 FileWriter fw = new FileWriter("/Users/Desktop/test"); // 创建缓冲字符流 BufferedWriter bw = new BufferedWriter(fw); // 写入数据到缓冲区 bw.write("写入到缓冲区"); // 刷新缓冲区,把数据从缓冲区写入到文件 bw.flush(); // 关闭流 bw.close(); }// 使用字符缓冲流读取文件 public static void readBf () throws IOException { // 创建字符流 FileReader fr = new FileReader("/Users/Desktop/test"); // 创建缓冲字符流 BufferedReader br = new BufferedReader(fr); // 从缓冲区读取一行文件,如果读到文件末尾返回 null String line = br.readLine(); while (line != null) { System.out.println(line); line = br.readLine(); } // 关闭流 br.close(); } }

【Java|Java 学习笔记(十一)IO 流】输出结果:
写入到缓冲区

    推荐阅读