Java中有关流的知识

一、流的核心概念

  1. 什么是IO流
    IO = Input(输入) / Output(输出),是数据传输的通道,用来读写文件、网络、内存等数据,本质就是字节/字符的有序序列。
  • 输入流:读数据(程序←外部)
  • 输出流:写数据(程序→外部)
  1. 两大分类(顶层父类)

(1)字节流:操作字节 byte,万能流(图片、视频、文档、所有文件)

父类抽象类:

  • InputStream:所有字节输入流父类
  • OutputStream:所有字节输出流父类

(2)字符流:操作字符 char,只处理文本文件(.txt/.java/.md)

父类抽象类:

  • Reader:所有字符输入流父类
  • Writer:所有字符输出流父类

区分口诀:后缀是Stream=字节;Reader/Writer=字符

二、字节流详解

1. 文件字节流(基础)

FileInputStream 文件字节输入流(读文件)

构造方法:

// 传入文件路径
FileInputStream fis = new FileInputStream("a.txt");
// 传入File对象
File file = new File("a.txt");
FileInputStream fis = new FileInputStream(file);

核心读取方法:

  1. int read():读取1个字节,返回字节值;读到文件末尾返回 -1
  2. int read(byte[] b):批量读取到字节数组,返回读取长度,无数据返回-1
  3. close():关闭流,释放资源(必须执行)

示例读取文件:

import java.io.FileInputStream;
import java.io.IOException;

public class Test {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("test.txt");
        byte[] buf = new byte[1024]; // 缓冲区数组
        int len;
        // 循环读取
        while ((len = fis.read(buf)) != -1) {
            // 从数组0开始,打印len长度数据
            System.out.print(new String(buf, 0, len));
        }
        fis.close(); // 关闭流
    }
}

FileOutputStream 文件字节输出流(写文件)

构造:

// 覆盖写入:每次创建清空原有内容
FileOutputStream fos = new FileOutputStream("b.txt");
// 追加写入:第二个参数true,数据追加到文件末尾
FileOutputStream fos = new FileOutputStream("b.txt", true);

写入方法:

  1. write(int b):写入单个字节
  2. write(byte[] b):写入整个字节数组
  3. write(byte[] b,int off,int len):写入数组指定区间
  4. flush():刷新缓冲区(字节流缓冲区很小,可省略;字符流必须)
  5. close():关闭流(关闭前自动flush)

2. 缓冲字节流(提速,包装流)

底层自带缓冲区,减少磁盘IO,读写速度远高于普通文件流

  • BufferedInputStream 缓冲字节输入
  • BufferedOutputStream 缓冲字节输出

用法:包装原始文件流

FileInputStream fis = new FileInputStream("1.jpg");
BufferedInputStream bis = new BufferedInputStream(fis);

FileOutputStream fos = new FileOutputStream("copy.jpg");
BufferedOutputStream bos = new BufferedOutputStream(fos);

关闭规则:只关外层缓冲流,内层流会自动关闭。

3. 对象字节流(序列化)

实现对象读写,把对象存入文件/网络传输

  • ObjectInputStream:读对象(反序列化)
  • ObjectOutputStream:写对象(序列化)
    要求:实体类必须实现 Serializable 标记接口
class User implements Serializable {
    String name;
    int age;
}

核心方法:

  • writeObject(Object obj) 写对象
  • readObject() 读取对象,返回Object需要强转

三、字符流详解(只处理文本)

1. 文件字符流

FileReader 字符输入流

read() 读取单个字符,read(char[] cbuf) 批量读取字符数组

FileWriter 字符输出流

特有:自带字符缓冲区,写完必须flush()/close() 数据才会落地到文件

FileWriter fw = new FileWriter("c.txt");
fw.write("你好Java");
fw.flush(); // 刷新缓冲区,数据写入磁盘
fw.close();

2. 缓冲字符流(常用,带一行读写)

  • BufferedReader:字符缓冲输入
    独有方法:String readLine() 读取一整行字符串,无内容返回null
  • BufferedWriter:字符缓冲输出
    独有方法:newLine() 换行(跨平台兼容)

示例按行读写文本:

BufferedReader br = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("copy.txt"));

String line;
while ((line = br.readLine()) != null) {
    bw.write(line);
    bw.newLine(); // 换行
}
bw.flush();
bw.close();
br.close();

3. 转换流(字节 ↔ 字符桥梁,处理编码)

解决中文乱码核心类,可指定读写编码(UTF-8/GBK)

  • InputStreamReader:字节输入流转字符输入流
  • OutputStreamWriter:字符输出流转字节输出流

指定UTF-8读取文件:

FileInputStream fis = new FileInputStream("utf.txt");
// 字节流转字符流,指定编码
InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
BufferedReader br = new BufferedReader(isr);

四、IO流异常处理(标准写法 try-catch-finally / try-with-resources)

1. 传统finally(JDK7前)

finally中关闭流,防止资源泄漏

FileReader fr = null;
try {
    fr = new FileReader("a.txt");
    // 读写操作
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (fr != null) {
        try {
            fr.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2. try-with-resources(JDK7推荐,最简)

实现 AutoCloseable 接口的流,代码执行完毕自动关闭,无需手动close

// 流定义在try()括号内,自动释放
try (BufferedReader br = new BufferedReader(new FileReader("a.txt"))) {
    String s = br.readLine();
    System.out.println(s);
} catch (IOException e) {
    e.printStackTrace();
}

五、标准流(控制台输入输出)

属于字节流,系统默认流,无需手动关闭

  1. System.out:PrintStream 控制台输出
  2. System.in:InputStream 控制台键盘输入
  3. System.err:错误输出流

常用键盘读取包装:

Scanner sc = new Scanner(System.in);
// 或字符缓冲读取
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String input = br.readLine();

六、打印流 PrintStream / PrintWriter

只输出,不抛IO异常,自动刷新,开发常用

  • PrintStream:字节打印流(System.out本质就是它)
  • PrintWriter:字符打印流,可包装文件、流
    优势:print()/println() 支持任意数据类型自动转字符串

七、NIO(补充:JDK1.4非阻塞IO,区别传统BIO)

我们上面讲的全部是 BIO 同步阻塞IO(一个连接一个线程,读写阻塞)
NIO三大核心:Channel通道、Buffer缓冲区、Selector选择器,适合高并发网络编程。

八、高频面试区分点

  1. 字节流和字符流使用场景
    • 字节流:图片、视频、音频、压缩包、任意文件复制
    • 字符流:仅纯文本文件读写
  2. 缓冲流作用:内置缓冲区,减少磁盘IO交互,大幅提升读写性能
  3. flush()作用:清空内存缓冲区,把数据写入磁盘;字符流必须刷新
  4. 序列化条件:类实现Serializable接口,静态变量不会序列化
  5. 转换流作用:设置文件编码,解决中文乱码
  6. 关闭流顺序:先关外层包装流,外层关闭自动关闭内层原始流

九、文件复制通用模板(缓冲字节流,万能复制)

import java.io.*;

public class CopyFile {
    public static void main(String[] args) {
        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("source.jpg"));
             BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("target.jpg"))) {

            byte[] buf = new byte[1024 * 8]; // 8KB缓冲区
            int len;
            while ((len = bis.read(buf)) != -1) {
                bos.write(buf, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
posted @ 2026-06-28 23:24  李伯韬  阅读(2)  评论(0)    收藏  举报