【Java】IO流完全指南

Java IO流完全指南

摘要

Java IO流是输入输出操作的核心技术,包括字节流和字符流两大类。通过InputStream、OutputStream、Reader、Writer四大抽象类及其子类,实现文件读写、缓冲处理、对象序列化等功能。


目录

  1. IO流概述
  2. IO四大抽象类
  3. 文件读写操作
  4. 缓冲流
  5. 转换流
  6. File类
  7. 特殊流类型
  8. IO异常处理

IO流概述

IO流分类

按流的方向分类:

  • 输入流(Input):从数据源读取数据到程序
  • 输出流(Output):从程序写入数据到目标

按数据单位分类:

  • 字节流(Byte):以字节为单位处理数据,适用于所有文件类型
  • 字符流(Character):以字符为单位处理数据,适用于文本文件

IO流体系结构

markdown 复制代码
IO流体系
├── 字节流
│   ├── InputStream(输入)
│   └── OutputStream(输出)
└── 字符流
    ├── Reader(输入)
    └── Writer(输出)

IO四大抽象类

1. InputStream(字节输入流)

所有字节输入流的抽象超类。

构造方法
java 复制代码
InputStream()
主要方法
方法 返回类型 描述
available() int 返回可读取的字节数
close() void 关闭流,释放资源
mark(int readlimit) void 在流中标记当前位置
read() int 读取下一个字节,返回-1表示结束
read(byte[] b) int 读取字节到数组中
read(byte[] b, int off, int len) int 读取指定长度的字节
reset() void 重置到标记位置

2. OutputStream(字节输出流)

所有字节输出流的抽象超类。

构造方法
java 复制代码
OutputStream()
主要方法
方法 返回类型 描述
close() void 关闭流
flush() void 刷新并强制写出缓冲的字节
write(byte[] b) void 写入字节数组
write(byte[] b, int off, int len) void 写入字节数组的指定部分
write(int b) void 写入指定字节

3. Reader(字符输入流)

读取字符流的抽象类。

构造方法
java 复制代码
Reader()
Reader(Object lock)  // 指定同步锁
主要方法
方法 返回类型 描述
close() void 关闭流
read() int 读取单个字符
read(char[] cbuf) int 读取字符到数组
read(char[] cbuf, int off, int len) int 读取字符到数组指定位置
ready() boolean 判断是否准备好读取
skip(long n) long 跳过指定数量的字符

4. Writer(字符输出流)

写入字符流的抽象类。

构造方法
java 复制代码
Writer()
Writer(Object lock)  // 指定同步锁
主要方法
方法 返回类型 描述
close() void 关闭流
flush() void 刷新流
write(char[] cbuf) void 写入字符数组
write(int c) void 写入单个字符
write(String str) void 写入字符串

文件读写操作

字符文件操作

1. FileReader - 字符文件读取
java 复制代码
// 构造方法
FileReader(File file)
FileReader(String fileName)
2. FileWriter - 字符文件写入
java 复制代码
// 构造方法
FileWriter(String fileName)              // 覆盖写入
FileWriter(String fileName, boolean append)  // append=true表示追加
字符文件复制示例
java 复制代码
import java.io.*;

public class CopyText {
    public static void main(String[] args) throws IOException {
        FileReader fr = null;
        FileWriter fw = null;
        
        try {
            // 创建读取流与源文件关联
            fr = new FileReader("source.txt");
            // 创建写入流与目标文件关联
            fw = new FileWriter("target.txt");
            
            int ch;
            // 循环读取字符并写入
            while ((ch = fr.read()) != -1) {
                fw.write(ch);
            }
        } finally {
            // 关闭流资源
            if (fw != null) fw.close();
            if (fr != null) fr.close();
        }
    }
}

字节文件操作

1. FileInputStream - 字节文件读取
java 复制代码
// 构造方法
FileInputStream(File file)
FileInputStream(String name)

// 主要方法
available()     // 返回可读字节数
read()         // 读取单个字节
read(byte[] b) // 读取字节到数组
2. FileOutputStream - 字节文件写入
java 复制代码
// 构造方法
FileOutputStream(File file)
FileOutputStream(String name)

// 主要方法
write(byte[] b)                    // 写入字节数组
write(byte[] b, int off, int len)  // 写入字节数组的部分
write(int b)                       // 写入单个字节
字节文件复制示例(图片复制)
java 复制代码
import java.io.*;

public class CopyImage {
    public static void main(String[] args) {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        
        try {
            fis = new FileInputStream("source.jpg");
            fos = new FileOutputStream("target.jpg");
            
            byte[] buffer = new byte[1024];
            int len;
            
            while ((len = fis.read(buffer)) != -1) {
                fos.write(buffer, 0, len);
            }
        } catch (IOException e) {
            throw new RuntimeException("文件复制失败", e);
        } finally {
            try {
                if (fis != null) fis.close();
                if (fos != null) fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

缓冲流

缓冲流通过内置缓冲区提高IO操作效率,减少对底层系统的访问次数。

字符缓冲流

1. BufferedReader
java 复制代码
// 构造方法
BufferedReader(Reader in)
BufferedReader(Reader in, int sz)  // 指定缓冲区大小

// 特有方法
readLine()  // 读取一行文本
2. BufferedWriter
java 复制代码
// 构造方法
BufferedWriter(Writer out)
BufferedWriter(Writer out, int sz)

// 特有方法
newLine()  // 写入行分隔符
字符缓冲流示例
java 复制代码
import java.io.*;

public class BufferedCopyText {
    public static void main(String[] args) {
        BufferedReader bufr = null;
        BufferedWriter bufw = null;
        
        try {
            bufr = new BufferedReader(new FileReader("source.txt"));
            bufw = new BufferedWriter(new FileWriter("target.txt"));
            
            String line;
            while ((line = bufr.readLine()) != null) {
                bufw.write(line);
                bufw.newLine();  // 写入换行符
                bufw.flush();    // 刷新缓冲区
            }
        } catch (IOException e) {
            throw new RuntimeException("读写失败", e);
        } finally {
            try {
                if (bufr != null) bufr.close();
                if (bufw != null) bufw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

字节缓冲流

1. BufferedInputStream
java 复制代码
// 构造方法
BufferedInputStream(InputStream in)
BufferedInputStream(InputStream in, int size)
2. BufferedOutputStream
java 复制代码
// 构造方法
BufferedOutputStream(OutputStream out)
BufferedOutputStream(OutputStream out, int size)
字节缓冲流示例(音频复制)
java 复制代码
import java.io.*;

public class BufferedCopyAudio {
    public static void main(String[] args) {
        BufferedInputStream bufis = null;
        BufferedOutputStream bufos = null;
        
        try {
            bufis = new BufferedInputStream(new FileInputStream("source.mp3"));
            bufos = new BufferedOutputStream(new FileOutputStream("target.mp3"));
            
            int by;
            while ((by = bufis.read()) != -1) {
                bufos.write(by);
            }
        } catch (IOException e) {
            throw new RuntimeException("复制失败", e);
        } finally {
            try {
                if (bufis != null) bufis.close();
                if (bufos != null) bufos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

转换流

转换流是字节流与字符流之间的桥梁,主要用于字符编码转换。

1. InputStreamReader(字节流→字符流)

java 复制代码
// 构造方法
InputStreamReader(InputStream in)                    // 使用默认字符集
InputStreamReader(InputStream in, String charsetName)  // 指定字符集

// 主要方法
getEncoding()  // 返回字符编码名称

2. OutputStreamWriter(字符流→字节流)

java 复制代码
// 构造方法
OutputStreamWriter(OutputStream out)                    // 使用默认字符集
OutputStreamWriter(OutputStream out, String charsetName)  // 指定字符集

// 主要方法
getEncoding()  // 返回字符编码名称

转换流应用示例

java 复制代码
import java.io.*;

public class TransformStreamDemo {
    public static void main(String[] args) {
        BufferedReader bufr = null;
        BufferedWriter bufw = null;
        
        try {
            // 系统输入转为字符流,使用UTF-8编码
            bufr = new BufferedReader(
                new InputStreamReader(System.in, "UTF-8")
            );
            
            // 系统输出转为字符流,使用UTF-8编码
            bufw = new BufferedWriter(
                new OutputStreamWriter(System.out, "UTF-8")
            );
            
            String line;
            while ((line = bufr.readLine()) != null) {
                if ("exit".equals(line)) {
                    break;
                }
                
                // 转为大写并输出
                bufw.write(line.toUpperCase());
                bufw.newLine();
                bufw.flush();
            }
        } catch (IOException e) {
            throw new RuntimeException("处理失败", e);
        } finally {
            try {
                if (bufr != null) bufr.close();
                if (bufw != null) bufw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

File类

File类用于封装文件或文件夹,提供对文件系统的操作功能。

构造方法

java 复制代码
File(String pathname)                    // 通过路径名创建
File(String parent, String child)       // 通过父目录和子文件名创建
File(File parent, String child)         // 通过父File对象和子文件名创建

主要方法

创建和删除操作
方法 返回类型 描述
createNewFile() boolean 创建新文件
mkdir() boolean 创建目录
mkdirs() boolean 创建目录(包括必需的父目录)
delete() boolean 删除文件或目录
判断操作
方法 返回类型 描述
exists() boolean 判断是否存在
isFile() boolean 判断是否为文件
isDirectory() boolean 判断是否为目录
canRead() boolean 判断是否可读
canWrite() boolean 判断是否可写
获取信息
方法 返回类型 描述
getName() String 获取文件名
getPath() String 获取路径
getParent() String 获取父目录
length() long 获取文件大小
lastModified() long 获取最后修改时间
目录操作
方法 返回类型 描述
list() String[] 获取目录中文件名数组
listFiles() File[] 获取目录中文件对象数组

File类应用示例

1. 条件查找文件
java 复制代码
import java.io.*;

public class FileFilterDemo {
    public static void main(String[] args) {
        File dir = new File("C:\\Users\\Desktop");
        
        // 使用FilenameFilter过滤条件
        File[] jpgFiles = dir.listFiles(new FilenameFilter() {
            public boolean accept(File dir, String name) {
                return name.toLowerCase().endsWith(".jpg");
            }
        });
        
        // 输出找到的JPG文件
        if (jpgFiles != null) {
            for (File file : jpgFiles) {
                System.out.println(file.getName() + " - 大小: " + file.length() + " bytes");
            }
        }
    }
}
2. 递归遍历目录
java 复制代码
import java.io.*;

public class DirectoryTraversal {
    public static void main(String[] args) {
        File dir = new File("C:\\Projects");
        traverseDirectory(dir, 0);
    }
    
    public static void traverseDirectory(File dir, int level) {
        if (!dir.exists() || !dir.isDirectory()) {
            return;
        }
        
        // 打印目录名(带缩进)
        printWithIndent(dir.getName() + "/", level);
        
        File[] files = dir.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    traverseDirectory(file, level + 1);
                } else {
                    printWithIndent(file.getName(), level + 1);
                }
            }
        }
    }
    
    private static void printWithIndent(String text, int level) {
        for (int i = 0; i < level; i++) {
            System.out.print("  ");
        }
        System.out.println(text);
    }
}

特殊流类型

1. 打印流

打印流提供便捷的打印功能,可以打印各种数据类型。

PrintStream(字节打印流)
java 复制代码
// 构造方法
PrintStream(File file)
PrintStream(OutputStream out)
PrintStream(String fileName)

// 特有方法
print(Object obj)    // 打印对象
println(Object obj)  // 打印对象并换行
printf(String format, Object... args)  // 格式化打印
PrintWriter(字符打印流)
java 复制代码
// 构造方法
PrintWriter(File file)
PrintWriter(Writer out)
PrintWriter(String fileName)

2. 对象流(序列化)

对象流用于对象的序列化和反序列化操作。

前提条件

被序列化的类必须实现Serializable接口:

java 复制代码
import java.io.Serializable;

public class Person implements Serializable {
    private static final long serialVersionUID = 1L;
    
    private String name;
    private int age;
    
    // 构造方法、getter、setter...
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    @Override
    public String toString() {
        return name + ":" + age;
    }
}
ObjectOutputStream(对象输出流)
java 复制代码
import java.io.*;

public class ObjectSerialize {
    public static void main(String[] args) {
        try (ObjectOutputStream oos = new ObjectOutputStream(
                new FileOutputStream("person.dat"))) {
            
            Person person = new Person("张三", 25);
            oos.writeObject(person);
            System.out.println("对象序列化完成");
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
ObjectInputStream(对象输入流)
java 复制代码
import java.io.*;

public class ObjectDeserialize {
    public static void main(String[] args) {
        try (ObjectInputStream ois = new ObjectInputStream(
                new FileInputStream("person.dat"))) {
            
            Person person = (Person) ois.readObject();
            System.out.println("反序列化对象: " + person);
            
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

3. 数据流

数据流用于读写基本数据类型。

DataOutputStream
java 复制代码
import java.io.*;

public class DataStreamWrite {
    public static void main(String[] args) {
        try (DataOutputStream dos = new DataOutputStream(
                new FileOutputStream("data.dat"))) {
            
            dos.writeInt(100);
            dos.writeDouble(3.14);
            dos.writeUTF("Hello World");
            dos.writeBoolean(true);
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
DataInputStream
java 复制代码
import java.io.*;

public class DataStreamRead {
    public static void main(String[] args) {
        try (DataInputStream dis = new DataInputStream(
                new FileInputStream("data.dat"))) {
            
            int num = dis.readInt();
            double pi = dis.readDouble();
            String str = dis.readUTF();
            boolean flag = dis.readBoolean();
            
            System.out.println("int: " + num);
            System.out.println("double: " + pi);
            System.out.println("String: " + str);
            System.out.println("boolean: " + flag);
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

4. RandomAccessFile

随机访问文件类,支持对文件的随机读写。

基本用法
java 复制代码
import java.io.*;

public class RandomAccessFileDemo {
    public static void main(String[] args) {
        try {
            // 写入数据
            writeData();
            // 读取数据
            readData();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    public static void writeData() throws IOException {
        try (RandomAccessFile raf = new RandomAccessFile("random.dat", "rw")) {
            raf.writeUTF("张三");
            raf.writeInt(25);
            raf.writeUTF("李四");
            raf.writeInt(30);
        }
    }
    
    public static void readData() throws IOException {
        try (RandomAccessFile raf = new RandomAccessFile("random.dat", "r")) {
            // 移动到指定位置读取
            raf.seek(0);
            String name1 = raf.readUTF();
            int age1 = raf.readInt();
            System.out.println(name1 + ": " + age1);
            
            String name2 = raf.readUTF();
            int age2 = raf.readInt();
            System.out.println(name2 + ": " + age2);
        }
    }
}

IO异常处理

常见IO异常类型

异常类 描述
IOException IO操作的通用异常
FileNotFoundException 文件未找到异常
EOFException 意外到达文件或流末尾
UTFDataFormatException UTF格式数据异常
InvalidClassException 序列化版本不匹配

IO异常处理最佳实践

1. try-with-resources(推荐)
java 复制代码
public class IOExceptionHandling {
    public static void copyFile(String source, String target) {
        // 自动资源管理
        try (FileInputStream fis = new FileInputStream(source);
             FileOutputStream fos = new FileOutputStream(target)) {
            
            byte[] buffer = new byte[1024];
            int len;
            while ((len = fis.read(buffer)) != -1) {
                fos.write(buffer, 0, len);
            }
            
        } catch (FileNotFoundException e) {
            System.err.println("文件未找到: " + e.getMessage());
        } catch (IOException e) {
            System.err.println("IO操作失败: " + e.getMessage());
        }
    }
}
2. 传统异常处理方式
java 复制代码
public class TraditionalExceptionHandling {
    public static void copyFile(String source, String target) {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        
        try {
            fis = new FileInputStream(source);
            fos = new FileOutputStream(target);
            
            byte[] buffer = new byte[1024];
            int len;
            while ((len = fis.read(buffer)) != -1) {
                fos.write(buffer, 0, len);
            }
            
        } catch (FileNotFoundException e) {
            System.err.println("文件未找到: " + e.getMessage());
        } catch (IOException e) {
            System.err.println("IO操作失败: " + e.getMessage());
        } finally {
            // 确保资源被正确关闭
            try {
                if (fis != null) fis.close();
            } catch (IOException e) {
                System.err.println("关闭输入流失败: " + e.getMessage());
            }
            
            try {
                if (fos != null) fos.close();
            } catch (IOException e) {
                System.err.println("关闭输出流失败: " + e.getMessage());
            }
        }
    }
}

总结

IO流选择指南

场景 推荐流类型 说明
文本文件读写 FileReader/FileWriter + 缓冲流 字符流处理文本更方便
二进制文件操作 FileInputStream/FileOutputStream + 缓冲流 字节流处理二进制数据
网络数据传输 字节流 + 转换流 网络传输基于字节
对象持久化 ObjectInputStream/ObjectOutputStream 序列化和反序列化
大文件处理 缓冲流 提高效率
随机访问 RandomAccessFile 支持随机定位

性能优化建议

  1. 使用缓冲流:减少系统调用次数,提高IO效率
  2. 合理设置缓冲区大小:根据文件大小和内存情况调整
  3. 及时关闭流:使用try-with-resources或finally块
  4. 批量操作:使用数组读写而非单个字节/字符
  5. 避免频繁的小数据读写:合并读写操作

最佳实践

  1. 资源管理:始终确保流被正确关闭
  2. 异常处理:捕获具体的异常类型并提供有意义的错误信息
  3. 编码处理:明确指定字符编码,避免乱码问题
  4. 线程安全:IO流通常不是线程安全的,多线程环境需要同步
  5. 内存管理:处理大文件时注意内存使用,避免一次性读取过多数据

通过掌握Java IO流的核心概念和常用类,可以高效地处理各种输入输出操作,为Java应用程序提供强大的文件处理能力。

相关推荐
鱼跃鹰飞1 小时前
设计模式系列:工厂模式
java·设计模式·系统架构
a努力。1 小时前
国家电网Java面试被问:混沌工程在分布式系统中的应用
java·开发语言·数据库·git·mysql·面试·职场和发展
Yvonne爱编码1 小时前
Java 四大内部类全解析:从设计本质到实战应用
java·开发语言·python
J2虾虾1 小时前
SpringBoot和mybatis Plus不兼容报错的问题
java·spring boot·mybatis
毕设源码-郭学长2 小时前
【开题答辩全过程】以 基于springboot 的豪华婚车租赁系统的设计与实现为例,包含答辩的问题和答案
java·spring boot·后端
Loo国昌4 小时前
深入理解 FastAPI:Python高性能API框架的完整指南
开发语言·人工智能·后端·python·langchain·fastapi
Tao____4 小时前
通用性物联网平台
java·物联网·mqtt·低代码·开源
曹轲恒4 小时前
SpringBoot整合SpringMVC(上)
java·spring boot·spring
JH30735 小时前
Java Spring中@AllArgsConstructor注解引发的依赖注入异常解决
java·开发语言·spring
码农水水5 小时前
米哈游Java面试被问:机器学习模型的在线服务和A/B测试
java·开发语言·数据库·spring boot·后端·机器学习·word