【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应用程序提供强大的文件处理能力。

相关推荐
Java水解17 小时前
Spring Boot:Java开发的神奇加速器(二)
spring boot·后端
sunbin17 小时前
Eclipse 数据空间组件-最小化运行环境MVD_of_EDC-10
后端
问道飞鱼17 小时前
【Rust编程】Cargo 工具详解:从基础到高级的完整指南
开发语言·后端·rust·cargo
zhaokuner17 小时前
14-有界上下文-DDD领域驱动设计
java·开发语言·设计模式·架构
信码由缰17 小时前
停止编写Excel规格文档:企业级Java开发的Markdown先行方法
java·ai编程·markdown
k***921618 小时前
【c++】多态
java·开发语言·c++
西敏寺的乐章18 小时前
ThreadLocal / InheritableThreadLocal / TransmittableThreadLocal(TTL)学习总结
java·开发语言·网络
小毅&Nora18 小时前
【Java线程安全实战】⑤ 原子类(Atomic)深度解析:无锁编程(Lock-Free)的终极奥义(增强版)
java·多线程·原子操作
深盾科技18 小时前
C++ 中 std::error_code 的应用与实践
java·前端·c++