Skip to content

Java I/O 流

Java I/O(输入/输出)流是Java中处理数据输入和输出的核心机制。通过I/O流,程序可以读取文件、写入文件、从网络接收数据或向网络发送数据。

字节流与字符流

Java I/O流主要分为两大类:字节流和字符流。字节流以字节为单位处理数据,适用于处理二进制数据;字符流以字符为单位处理数据,适用于处理文本数据。

字节流

字节流的基类是InputStreamOutputStream,它们是所有字节流类的父类。

java
import java.io.*;

// 字节流示例
public class ByteStreamExample {
    public static void main(String[] args) {
        System.out.println("=== 字节流示例 ===");
        
        // 1. 文件字节流 - FileInputStream和FileOutputStream
        fileByteStreamExample();
        
        // 2. 缓冲字节流 - BufferedInputStream和BufferedOutputStream
        bufferedByteStreamExample();
        
        // 3. 数据字节流 - DataInputStream和DataOutputStream
        dataByteStreamExample();
        
        // 4. 对象字节流 - ObjectInputStream和ObjectOutputStream
        objectByteStreamExample();
    }
    
    // 文件字节流示例
    public static void fileByteStreamExample() {
        System.out.println("\n--- 文件字节流示例 ---");
        
        String fileName = "byte_example.txt";
        String content = "Hello, Java Byte Stream!\n这是一个字节流示例。";
        
        // 写入文件
        try (FileOutputStream fos = new FileOutputStream(fileName)) {
            byte[] bytes = content.getBytes("UTF-8");
            fos.write(bytes);
            System.out.println("数据已写入文件: " + fileName);
        } catch (IOException e) {
            System.err.println("写入文件时发生错误: " + e.getMessage());
        }
        
        // 读取文件
        try (FileInputStream fis = new FileInputStream(fileName)) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            System.out.print("从文件读取的数据: ");
            while ((bytesRead = fis.read(buffer)) != -1) {
                System.out.print(new String(buffer, 0, bytesRead, "UTF-8"));
            }
            System.out.println();
        } catch (IOException e) {
            System.err.println("读取文件时发生错误: " + e.getMessage());
        }
    }
    
    // 缓冲字节流示例
    public static void bufferedByteStreamExample() {
        System.out.println("\n--- 缓冲字节流示例 ---");
        
        String fileName = "buffered_example.txt";
        
        // 使用缓冲输出流写入大量数据
        try (FileOutputStream fos = new FileOutputStream(fileName);
             BufferedOutputStream bos = new BufferedOutputStream(fos)) {
            
            // 写入大量数据
            for (int i = 0; i < 1000; i++) {
                String line = "这是第" + (i + 1) + "行数据\n";
                bos.write(line.getBytes("UTF-8"));
            }
            // 缓冲流会自动刷新缓冲区
            System.out.println("大量数据已写入文件: " + fileName);
        } catch (IOException e) {
            System.err.println("写入文件时发生错误: " + e.getMessage());
        }
        
        // 使用缓冲输入流读取数据
        try (FileInputStream fis = new FileInputStream(fileName);
             BufferedInputStream bis = new BufferedInputStream(fis)) {
            
            long startTime = System.currentTimeMillis();
            byte[] buffer = new byte[1024];
            int totalBytes = 0;
            int bytesRead;
            
            while ((bytesRead = bis.read(buffer)) != -1) {
                totalBytes += bytesRead;
            }
            
            long endTime = System.currentTimeMillis();
            System.out.println("读取字节数: " + totalBytes);
            System.out.println("读取耗时: " + (endTime - startTime) + " ms");
        } catch (IOException e) {
            System.err.println("读取文件时发生错误: " + e.getMessage());
        }
    }
    
    // 数据字节流示例
    public static void dataByteStreamExample() {
        System.out.println("\n--- 数据字节流示例 ---");
        
        String fileName = "data_example.dat";
        
        // 使用DataOutputStream写入各种数据类型
        try (FileOutputStream fos = new FileOutputStream(fileName);
             DataOutputStream dos = new DataOutputStream(fos)) {
            
            dos.writeUTF("Java数据流示例");
            dos.writeInt(12345);
            dos.writeDouble(3.14159);
            dos.writeBoolean(true);
            dos.writeFloat(2.5f);
            
            System.out.println("不同类型的数据已写入文件");
        } catch (IOException e) {
            System.err.println("写入数据时发生错误: " + e.getMessage());
        }
        
        // 使用DataInputStream读取数据
        try (FileInputStream fis = new FileInputStream(fileName);
             DataInputStream dis = new DataInputStream(fis)) {
            
            String text = dis.readUTF();
            int number = dis.readInt();
            double pi = dis.readDouble();
            boolean flag = dis.readBoolean();
            float value = dis.readFloat();
            
            System.out.println("读取的数据:");
            System.out.println("  字符串: " + text);
            System.out.println("  整数: " + number);
            System.out.println("  双精度浮点数: " + pi);
            System.out.println("  布尔值: " + flag);
            System.out.println("  单精度浮点数: " + value);
        } catch (IOException e) {
            System.err.println("读取数据时发生错误: " + e.getMessage());
        }
    }
    
    // 对象字节流示例
    public static void objectByteStreamExample() {
        System.out.println("\n--- 对象字节流示例 ---");
        
        String fileName = "object_example.ser";
        
        // 创建要序列化的对象
        Person person = new Person("张三", 25, "zhangsan@example.com");
        Book book = new Book("Java编程思想", "Bruce Eckel", 89.0);
        
        // 序列化对象
        try (FileOutputStream fos = new FileOutputStream(fileName);
             ObjectOutputStream oos = new ObjectOutputStream(fos)) {
            
            oos.writeObject(person);
            oos.writeObject(book);
            
            System.out.println("对象已序列化到文件: " + fileName);
            System.out.println("序列化的对象:");
            System.out.println("  " + person);
            System.out.println("  " + book);
        } catch (IOException e) {
            System.err.println("序列化对象时发生错误: " + e.getMessage());
        }
        
        // 反序列化对象
        try (FileInputStream fis = new FileInputStream(fileName);
             ObjectInputStream ois = new ObjectInputStream(fis)) {
            
            Person deserializedPerson = (Person) ois.readObject();
            Book deserializedBook = (Book) ois.readObject();
            
            System.out.println("反序列化的对象:");
            System.out.println("  " + deserializedPerson);
            System.out.println("  " + deserializedBook);
            
            // 验证对象是否完全恢复
            System.out.println("对象恢复验证:");
            System.out.println("  姓名匹配: " + person.getName().equals(deserializedPerson.getName()));
            System.out.println("  年龄匹配: " + (person.getAge() == deserializedPerson.getAge()));
            System.out.println("  书籍名称匹配: " + book.getTitle().equals(deserializedBook.getTitle()));
        } catch (IOException | ClassNotFoundException e) {
            System.err.println("反序列化对象时发生错误: " + e.getMessage());
        }
    }
}

// 用于序列化的Person类
class Person implements Serializable {
    private static final long serialVersionUID = 1L;
    
    private String name;
    private int age;
    private String email;
    
    public Person(String name, int age, String email) {
        this.name = name;
        this.age = age;
        this.email = email;
    }
    
    // getter方法
    public String getName() { return name; }
    public int getAge() { return age; }
    public String getEmail() { return email; }
    
    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + ", email='" + email + "'}";
    }
}

// 用于序列化的Book类
class Book implements Serializable {
    private static final long serialVersionUID = 1L;
    
    private String title;
    private String author;
    private double price;
    
    public Book(String title, String author, double price) {
        this.title = title;
        this.author = author;
        this.price = price;
    }
    
    // getter方法
    public String getTitle() { return title; }
    public String getAuthor() { return author; }
    public double getPrice() { return price; }
    
    @Override
    public String toString() {
        return "Book{title='" + title + "', author='" + author + "', price=" + price + "}";
    }
}

字符流

字符流的基类是ReaderWriter,它们专门用于处理字符数据,自动处理字符编码转换。

java
import java.io.*;
import java.nio.charset.StandardCharsets;

// 字符流示例
public class CharacterStreamExample {
    public static void main(String[] args) {
        System.out.println("=== 字符流示例 ===");
        
        // 1. 文件字符流 - FileReader和FileWriter
        fileCharacterStreamExample();
        
        // 2. 缓冲字符流 - BufferedReader和BufferedWriter
        bufferedCharacterStreamExample();
        
        // 3. PrintWriter示例
        printWriterExample();
        
        // 4. InputStreamReader和OutputStreamWriter示例
        streamConverterExample();
    }
    
    // 文件字符流示例
    public static void fileCharacterStreamExample() {
        System.out.println("\n--- 文件字符流示例 ---");
        
        String fileName = "char_example.txt";
        String content = "Hello, Java Character Stream!\n这是一个字符流示例。\n支持中文字符的正确处理。";
        
        // 使用FileWriter写入文件
        try (FileWriter writer = new FileWriter(fileName, StandardCharsets.UTF_8)) {
            writer.write(content);
            System.out.println("文本已写入文件: " + fileName);
        } catch (IOException e) {
            System.err.println("写入文件时发生错误: " + e.getMessage());
        }
        
        // 使用FileReader读取文件
        try (FileReader reader = new FileReader(fileName, StandardCharsets.UTF_8)) {
            char[] buffer = new char[1024];
            int charsRead;
            System.out.print("从文件读取的文本: ");
            while ((charsRead = reader.read(buffer)) != -1) {
                System.out.print(new String(buffer, 0, charsRead));
            }
            System.out.println();
        } catch (IOException e) {
            System.err.println("读取文件时发生错误: " + e.getMessage());
        }
    }
    
    // 缓冲字符流示例
    public static void bufferedCharacterStreamExample() {
        System.out.println("\n--- 缓冲字符流示例 ---");
        
        String fileName = "buffered_char_example.txt";
        
        // 使用BufferedWriter写入文件
        try (FileWriter fileWriter = new FileWriter(fileName, StandardCharsets.UTF_8);
             BufferedWriter bufferedWriter = new BufferedWriter(fileWriter)) {
            
            // 写入多行文本
            for (int i = 1; i <= 100; i++) {
                bufferedWriter.write("这是第" + i + "行文本");
                bufferedWriter.newLine(); // 写入换行符
            }
            
            // 使用write方法写入字符数组
            char[] chars = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!'};
            bufferedWriter.write(chars);
            bufferedWriter.newLine();
            
            System.out.println("多行文本已写入文件: " + fileName);
        } catch (IOException e) {
            System.err.println("写入文件时发生错误: " + e.getMessage());
        }
        
        // 使用BufferedReader读取文件
        try (FileReader fileReader = new FileReader(fileName, StandardCharsets.UTF_8);
             BufferedReader bufferedReader = new BufferedReader(fileReader)) {
            
            String line;
            int lineCount = 0;
            int charCount = 0;
            
            // 逐行读取
            while ((line = bufferedReader.readLine()) != null) {
                lineCount++;
                charCount += line.length();
                // 仅打印前5行和最后一行
                if (lineCount <= 5 || lineCount == 101) {
                    System.out.println("第" + lineCount + "行: " + line);
                } else if (lineCount == 6) {
                    System.out.println("...");
                }
            }
            
            System.out.println("总行数: " + lineCount);
            System.out.println("总字符数: " + charCount);
        } catch (IOException e) {
            System.err.println("读取文件时发生错误: " + e.getMessage());
        }
    }
    
    // PrintWriter示例
    public static void printWriterExample() {
        System.out.println("\n--- PrintWriter示例 ---");
        
        String fileName = "print_example.txt";
        
        // 使用PrintWriter格式化输出
        try (PrintWriter printWriter = new PrintWriter(
                new BufferedWriter(new FileWriter(fileName, StandardCharsets.UTF_8)))) {
            
            // 打印各种数据类型
            printWriter.println("=== 学生成绩单 ===");
            printWriter.printf("%-10s %-10s %-10s%n", "姓名", "科目", "成绩");
            printWriter.println("------------------------");
            
            // 打印学生成绩
            printWriter.printf("%-10s %-10s %-10.1f%n", "张三", "数学", 95.5);
            printWriter.printf("%-10s %-10s %-10.1f%n", "张三", "英语", 87.0);
            printWriter.printf("%-10s %-10s %-10.1f%n", "李四", "数学", 92.0);
            printWriter.printf("%-10s %-10s %-10.1f%n", "李四", "英语", 88.5);
            
            // 计算并打印平均分
            printWriter.println();
            printWriter.println("平均分:");
            printWriter.printf("%-10s %-10s %-10.2f%n", "张三", "平均", (95.5 + 87.0) / 2);
            printWriter.printf("%-10s %-10s %-10.2f%n", "李四", "平均", (92.0 + 88.5) / 2);
            
            System.out.println("格式化数据已写入文件: " + fileName);
        } catch (IOException e) {
            System.err.println("写入文件时发生错误: " + e.getMessage());
        }
        
        // 读取并显示文件内容
        try (BufferedReader reader = new BufferedReader(
                new FileReader(fileName, StandardCharsets.UTF_8))) {
            
            String line;
            System.out.println("文件内容:");
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            System.err.println("读取文件时发生错误: " + e.getMessage());
        }
    }
    
    // InputStreamReader和OutputStreamWriter示例
    public static void streamConverterExample() {
        System.out.println("\n--- 字符流转换器示例 ---");
        
        String fileName = "converter_example.txt";
        
        // 使用OutputStreamWriter指定编码写入
        try (FileOutputStream fos = new FileOutputStream(fileName);
             OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8)) {
            
            String content = "这是使用OutputStreamWriter写入的内容\n支持指定字符编码\n可以正确处理中文等Unicode字符";
            osw.write(content);
            
            System.out.println("使用指定编码写入文件: " + fileName);
        } catch (IOException e) {
            System.err.println("写入文件时发生错误: " + e.getMessage());
        }
        
        // 使用InputStreamReader指定编码读取
        try (FileInputStream fis = new FileInputStream(fileName);
             InputStreamReader isr = new InputStreamReader(fis, StandardCharsets.UTF_8)) {
            
            char[] buffer = new char[1024];
            int charsRead;
            System.out.print("使用指定编码读取的内容: ");
            while ((charsRead = isr.read(buffer)) != -1) {
                System.out.print(new String(buffer, 0, charsRead));
            }
            System.out.println();
        } catch (IOException e) {
            System.err.println("读取文件时发生错误: " + e.getMessage());
        }
        
        // 演示不同编码的效果
        demonstrateEncoding();
    }
    
    // 演示不同编码的效果
    public static void demonstrateEncoding() {
        System.out.println("\n--- 编码演示 ---");
        
        String text = "Hello 世界 🌍";
        System.out.println("原始文本: " + text);
        
        // 不同编码的字节长度
        try {
            byte[] utf8Bytes = text.getBytes(StandardCharsets.UTF_8);
            byte[] utf16Bytes = text.getBytes(StandardCharsets.UTF_16);
            byte[] isoBytes = text.getBytes(StandardCharsets.ISO_8859_1);
            
            System.out.println("UTF-8编码字节数: " + utf8Bytes.length);
            System.out.println("UTF-16编码字节数: " + utf16Bytes.length);
            System.out.println("ISO-8859-1编码字节数: " + isoBytes.length);
            
            // 使用错误编码读取会出现乱码
            String wrongDecode = new String(utf8Bytes, StandardCharsets.ISO_8859_1);
            System.out.println("使用错误编码读取: " + wrongDecode);
        } catch (Exception e) {
            System.err.println("编码演示时发生错误: " + e.getMessage());
        }
    }
}

文件操作(File 类)

File类是Java中表示文件和目录路径名的抽象表示形式,它提供了许多用于文件和目录操作的方法。

java
import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Date;

// File类操作示例
public class FileExample {
    public static void main(String[] args) {
        System.out.println("=== File类操作示例 ===");
        
        // 1. File类基本操作
        basicFileOperations();
        
        // 2. 目录操作
        directoryOperations();
        
        // 3. 文件过滤和查找
        fileFiltering();
        
        // 4. 文件属性操作
        fileAttributes();
        
        // 5. 临时文件操作
        temporaryFiles();
        
        // 6. 文件路径操作
        pathOperations();
    }
    
    // File类基本操作
    public static void basicFileOperations() {
        System.out.println("\n--- File类基本操作 ---");
        
        // 创建File对象的多种方式
        File file1 = new File("example.txt");
        File file2 = new File("directory", "example.txt");
        File file3 = new File("directory/example.txt");
        File file4 = new File(new File("directory"), "example.txt");
        
        System.out.println("File对象创建方式:");
        System.out.println("  相对路径: " + file1.getPath());
        System.out.println("  父目录+文件名: " + file2.getPath());
        System.out.println("  完整路径: " + file3.getPath());
        System.out.println("  File对象+文件名: " + file4.getPath());
        
        // 文件创建和删除
        try {
            File testFile = new File("test_file.txt");
            
            // 创建新文件
            if (testFile.createNewFile()) {
                System.out.println("文件创建成功: " + testFile.getAbsolutePath());
            } else {
                System.out.println("文件已存在: " + testFile.getAbsolutePath());
            }
            
            // 写入一些内容
            try (FileWriter writer = new FileWriter(testFile)) {
                writer.write("这是测试文件的内容\n");
                writer.write("创建时间: " + new Date());
            }
            
            // 文件信息
            System.out.println("文件信息:");
            System.out.println("  绝对路径: " + testFile.getAbsolutePath());
            System.out.println("  规范路径: " + testFile.getCanonicalPath());
            System.out.println("  文件名: " + testFile.getName());
            System.out.println("  父目录: " + testFile.getParent());
            System.out.println("  文件大小: " + testFile.length() + " 字节");
            System.out.println("  是否存在: " + testFile.exists());
            System.out.println("  是否为文件: " + testFile.isFile());
            System.out.println("  是否为目录: " + testFile.isDirectory());
            System.out.println("  最后修改时间: " + new Date(testFile.lastModified()));
            
            // 删除文件
            if (testFile.delete()) {
                System.out.println("文件删除成功: " + testFile.getPath());
            } else {
                System.out.println("文件删除失败: " + testFile.getPath());
            }
        } catch (IOException e) {
            System.err.println("文件操作时发生错误: " + e.getMessage());
        }
    }
    
    // 目录操作
    public static void directoryOperations() {
        System.out.println("\n--- 目录操作 ---");
        
        // 创建目录
        File dir = new File("test_directory");
        
        if (dir.mkdir()) {
            System.out.println("目录创建成功: " + dir.getAbsolutePath());
        } else {
            System.out.println("目录已存在或创建失败: " + dir.getAbsolutePath());
        }
        
        // 创建多级目录
        File nestedDir = new File("parent/child/grandchild");
        if (nestedDir.mkdirs()) {
            System.out.println("多级目录创建成功: " + nestedDir.getAbsolutePath());
        } else {
            System.out.println("多级目录已存在或创建失败: " + nestedDir.getAbsolutePath());
        }
        
        // 在目录中创建文件
        try {
            File file1 = new File(dir, "file1.txt");
            File file2 = new File(dir, "file2.txt");
            
            file1.createNewFile();
            file2.createNewFile();
            
            System.out.println("在目录中创建文件:");
            System.out.println("  " + file1.getName());
            System.out.println("  " + file2.getName());
            
            // 列出目录内容
            String[] files = dir.list();
            if (files != null) {
                System.out.println("目录内容:");
                for (String fileName : files) {
                    System.out.println("  " + fileName);
                }
            }
            
            // 使用File对象列出内容
            File[] fileObjects = dir.listFiles();
            if (fileObjects != null) {
                System.out.println("详细目录信息:");
                for (File file : fileObjects) {
                    System.out.printf("  %-20s %-10s %-20s%n", 
                        file.getName(), 
                        file.isDirectory() ? "<DIR>" : file.length() + " bytes",
                        new Date(file.lastModified()));
                }
            }
        } catch (IOException e) {
            System.err.println("目录操作时发生错误: " + e.getMessage());
        }
        
        // 删除目录(必须为空)
        File emptyDir = new File("empty_directory");
        if (emptyDir.mkdir()) {
            if (emptyDir.delete()) {
                System.out.println("空目录删除成功: " + emptyDir.getPath());
            } else {
                System.out.println("空目录删除失败: " + emptyDir.getPath());
            }
        }
    }
    
    // 文件过滤和查找
    public static void fileFiltering() {
        System.out.println("\n--- 文件过滤和查找 ---");
        
        // 创建测试目录和文件
        File testDir = new File("filter_test");
        testDir.mkdir();
        
        try {
            // 创建不同类型的测试文件
            new File(testDir, "document.txt").createNewFile();
            new File(testDir, "image.jpg").createNewFile();
            new File(testDir, "data.csv").createNewFile();
            new File(testDir, "archive.zip").createNewFile();
            new File(testDir, "script.js").createNewFile();
            new File(testDir, "style.css").createNewFile();
            
            // 使用FilenameFilter过滤
            String[] txtFiles = testDir.list(new FilenameFilter() {
                @Override
                public boolean accept(File dir, String name) {
                    return name.endsWith(".txt");
                }
            });
            
            System.out.println("文本文件 (.txt):");
            if (txtFiles != null) {
                for (String file : txtFiles) {
                    System.out.println("  " + file);
                }
            }
            
            // 使用FileFilter过滤
            File[] imageFiles = testDir.listFiles(new FileFilter() {
                @Override
                public boolean accept(File pathname) {
                    return pathname.isFile() && pathname.getName().endsWith(".jpg");
                }
            });
            
            System.out.println("图片文件 (.jpg):");
            if (imageFiles != null) {
                for (File file : imageFiles) {
                    System.out.println("  " + file.getName());
                }
            }
            
            // Lambda表达式过滤(Java 8+)
            File[] largeFiles = testDir.listFiles(file -> file.length() > 0);
            System.out.println("非空文件:");
            if (largeFiles != null) {
                for (File file : largeFiles) {
                    System.out.println("  " + file.getName() + " (" + file.length() + " bytes)");
                }
            }
            
        } catch (IOException e) {
            System.err.println("文件过滤操作时发生错误: " + e.getMessage());
        }
    }
    
    // 文件属性操作
    public static void fileAttributes() {
        System.out.println("\n--- 文件属性操作 ---");
        
        try {
            File file = new File("attribute_test.txt");
            if (file.createNewFile()) {
                System.out.println("创建测试文件: " + file.getName());
            }
            
            // 设置文件属性
            System.out.println("文件属性:");
            System.out.println("  可读: " + file.canRead());
            System.out.println("  可写: " + file.canWrite());
            System.out.println("  可执行: " + file.canExecute());
            
            // 修改文件时间戳
            long newTime = System.currentTimeMillis() - 24 * 60 * 60 * 1000; // 24小时前
            if (file.setLastModified(newTime)) {
                System.out.println("修改最后修改时间成功");
            }
            
            // 使用NIO.2获取更详细的文件属性
            Path path = file.toPath();
            BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);
            
            System.out.println("详细文件属性 (NIO.2):");
            System.out.println("  创建时间: " + attrs.creationTime());
            System.out.println("  最后访问时间: " + attrs.lastAccessTime());
            System.out.println("  最后修改时间: " + attrs.lastModifiedTime());
            System.out.println("  是否为目录: " + attrs.isDirectory());
            System.out.println("  是否为常规文件: " + attrs.isRegularFile());
            System.out.println("  是否为符号链接: " + attrs.isSymbolicLink());
            System.out.println("  文件大小: " + attrs.size() + " 字节");
            
        } catch (IOException e) {
            System.err.println("文件属性操作时发生错误: " + e.getMessage());
        }
    }
    
    // 临时文件操作
    public static void temporaryFiles() {
        System.out.println("\n--- 临时文件操作 ---");
        
        try {
            // 创建临时文件
            File tempFile = File.createTempFile("temp_", ".txt");
            System.out.println("临时文件创建成功: " + tempFile.getAbsolutePath());
            
            // 写入临时文件
            try (FileWriter writer = new FileWriter(tempFile)) {
                writer.write("这是一个临时文件\n");
                writer.write("程序退出时应该被删除");
            }
            
            // 读取临时文件
            try (BufferedReader reader = new BufferedReader(new FileReader(tempFile))) {
                String line;
                System.out.println("临时文件内容:");
                while ((line = reader.readLine()) != null) {
                    System.out.println("  " + line);
                }
            }
            
            // 设置退出时删除
            tempFile.deleteOnExit();
            System.out.println("已设置程序退出时删除临时文件");
            
            // 创建临时目录
            Path tempDir = Files.createTempDirectory("temp_dir_");
            System.out.println("临时目录创建成功: " + tempDir.toAbsolutePath());
            
            // 在临时目录中创建文件
            Path tempFileInDir = tempDir.resolve("test.txt");
            Files.write(tempFileInDir, "临时目录中的文件".getBytes(StandardCharsets.UTF_8));
            System.out.println("临时目录中的文件: " + tempFileInDir.toAbsolutePath());
            
            // 设置临时目录退出时删除
            tempDir.toFile().deleteOnExit();
            tempFileInDir.toFile().deleteOnExit();
            
        } catch (IOException e) {
            System.err.println("临时文件操作时发生错误: " + e.getMessage());
        }
    }
    
    // 文件路径操作
    public static void pathOperations() {
        System.out.println("\n--- 文件路径操作 ---");
        
        // 使用不同分隔符
        String path1 = "dir1" + File.separator + "dir2" + File.separator + "file.txt";
        String path2 = "dir1/dir2/file.txt"; // Unix风格
        String path3 = "dir1\\dir2\\file.txt"; // Windows风格
        
        System.out.println("不同分隔符的路径:");
        System.out.println("  系统分隔符: " + path1);
        System.out.println("  Unix风格: " + path2);
        System.out.println("  Windows风格: " + path3);
        
        // 路径信息提取
        File file = new File("/home/user/documents/report.pdf");
        System.out.println("路径信息:");
        System.out.println("  完整路径: " + file.getPath());
        System.out.println("  绝对路径: " + file.getAbsolutePath());
        System.out.println("  文件名: " + file.getName());
        System.out.println("  父目录: " + file.getParent());
        System.out.println("  不带扩展名的文件名: " + getFileNameWithoutExtension(file));
        System.out.println("  文件扩展名: " + getFileExtension(file));
        
        // 相对路径和绝对路径转换
        File relativeFile = new File("data/config.xml");
        System.out.println("相对路径转换:");
        System.out.println("  相对路径: " + relativeFile.getPath());
        System.out.println("  绝对路径: " + relativeFile.getAbsolutePath());
        System.out.println("  规范路径: " + relativeFile.getCanonicalPath());
    }
    
    // 获取不带扩展名的文件名
    public static String getFileNameWithoutExtension(File file) {
        String fileName = file.getName();
        int dotIndex = fileName.lastIndexOf('.');
        return dotIndex > 0 ? fileName.substring(0, dotIndex) : fileName;
    }
    
    // 获取文件扩展名
    public static String getFileExtension(File file) {
        String fileName = file.getName();
        int dotIndex = fileName.lastIndexOf('.');
        return dotIndex > 0 ? fileName.substring(dotIndex + 1) : "";
    }
}

// 文件工具类
class FileUtils {
    // 复制文件
    public static void copyFile(File source, File destination) throws IOException {
        try (FileInputStream fis = new FileInputStream(source);
             FileOutputStream fos = new FileOutputStream(destination);
             BufferedInputStream bis = new BufferedInputStream(fis);
             BufferedOutputStream bos = new BufferedOutputStream(fos)) {
            
            byte[] buffer = new byte[8192];
            int bytesRead;
            while ((bytesRead = bis.read(buffer)) != -1) {
                bos.write(buffer, 0, bytesRead);
            }
        }
    }
    
    // 递归删除目录
    public static void deleteDirectory(File directory) throws IOException {
        if (directory.isDirectory()) {
            File[] files = directory.listFiles();
            if (files != null) {
                for (File file : files) {
                    deleteDirectory(file);
                }
            }
        }
        
        if (!directory.delete()) {
            throw new IOException("无法删除文件或目录: " + directory.getPath());
        }
    }
    
    // 计算目录大小
    public static long getDirectorySize(File directory) {
        long size = 0;
        if (directory.isDirectory()) {
            File[] files = directory.listFiles();
            if (files != null) {
                for (File file : files) {
                    if (file.isFile()) {
                        size += file.length();
                    } else {
                        size += getDirectorySize(file);
                    }
                }
            }
        }
        return size;
    }
    
    // 查找文件
    public static File[] findFiles(File directory, String extension) {
        return directory.listFiles((dir, name) -> name.toLowerCase().endsWith(extension.toLowerCase()));
    }
}

// File工具类使用示例
public class FileUtilsExample {
    public static void main(String[] args) {
        System.out.println("=== File工具类使用示例 ===");
        
        try {
            // 创建测试目录和文件
            File testDir = new File("fileutils_test");
            testDir.mkdirs();
            
            File sourceFile = new File(testDir, "source.txt");
            try (FileWriter writer = new FileWriter(sourceFile)) {
                writer.write("这是源文件的内容\n用于测试文件复制功能\n包含多行文本");
            }
            
            // 测试文件复制
            File destFile = new File(testDir, "destination.txt");
            FileUtils.copyFile(sourceFile, destFile);
            System.out.println("文件复制成功");
            System.out.println("源文件大小: " + sourceFile.length() + " 字节");
            System.out.println("目标文件大小: " + destFile.length() + " 字节");
            
            // 创建子目录和文件
            File subDir = new File(testDir, "subdir");
            subDir.mkdir();
            new File(subDir, "subfile1.txt").createNewFile();
            new File(subDir, "subfile2.txt").createNewFile();
            
            // 计算目录大小
            long dirSize = FileUtils.getDirectorySize(testDir);
            System.out.println("目录总大小: " + dirSize + " 字节");
            
            // 查找特定类型文件
            File[] txtFiles = FileUtils.findFiles(testDir, ".txt");
            System.out.println("找到的.txt文件:");
            for (File file : txtFiles) {
                System.out.println("  " + file.getPath() + " (" + file.length() + " 字节)");
            }
            
            // 清理测试文件
            FileUtils.deleteDirectory(testDir);
            System.out.println("测试目录已清理");
            
        } catch (IOException e) {
            System.err.println("文件工具类测试时发生错误: " + e.getMessage());
        }
    }
}

缓冲流与转换流

缓冲流和转换流是Java I/O流体系中的重要组成部分,它们提供了额外的功能来提高I/O操作的效率和灵活性。

缓冲流

缓冲流通过在内存中维护缓冲区来减少实际的I/O操作次数,从而提高性能。

java
import java.io.*;
import java.nio.charset.StandardCharsets;

// 缓冲流示例
public class BufferedStreamExample {
    public static void main(String[] args) {
        System.out.println("=== 缓冲流示例 ===");
        
        // 1. 缓冲字节流性能对比
        byteStreamPerformanceComparison();
        
        // 2. 缓冲字符流性能对比
        characterStreamPerformanceComparison();
        
        // 3. 缓冲流的标记和重置功能
        markAndResetExample();
        
        // 4. 自定义缓冲区大小
        customBufferSizeExample();
    }
    
    // 缓冲字节流性能对比
    public static void byteStreamPerformanceComparison() {
        System.out.println("\n--- 缓冲字节流性能对比 ---");
        
        String fileName = "byte_performance_test.txt";
        int dataSize = 1000000; // 1MB数据
        
        // 创建测试数据
        try {
            createTestData(fileName, dataSize);
        } catch (IOException e) {
            System.err.println("创建测试数据时发生错误: " + e.getMessage());
            return;
        }
        
        // 不使用缓冲流读取
        long startTime = System.currentTimeMillis();
        long bytesRead = 0;
        
        try (FileInputStream fis = new FileInputStream(fileName)) {
            int data;
            while ((data = fis.read()) != -1) {
                bytesRead++;
            }
        } catch (IOException e) {
            System.err.println("读取文件时发生错误: " + e.getMessage());
        }
        
        long endTime = System.currentTimeMillis();
        long noBufferTime = endTime - startTime;
        
        System.out.println("不使用缓冲流:");
        System.out.println("  读取字节数: " + bytesRead);
        System.out.println("  耗时: " + noBufferTime + " ms");
        
        // 使用缓冲流读取
        startTime = System.currentTimeMillis();
        bytesRead = 0;
        
        try (FileInputStream fis = new FileInputStream(fileName);
             BufferedInputStream bis = new BufferedInputStream(fis)) {
            
            int data;
            while ((data = bis.read()) != -1) {
                bytesRead++;
            }
        } catch (IOException e) {
            System.err.println("读取文件时发生错误: " + e.getMessage());
        }
        
        endTime = System.currentTimeMillis();
        long bufferTime = endTime - startTime;
        
        System.out.println("使用缓冲流:");
        System.out.println("  读取字节数: " + bytesRead);
        System.out.println("  耗时: " + bufferTime + " ms");
        System.out.println("  性能提升: " + (noBufferTime > 0 ? (double) noBufferTime / bufferTime : "N/A") + " 倍");
        
        // 使用缓冲流批量读取
        startTime = System.currentTimeMillis();
        bytesRead = 0;
        
        try (FileInputStream fis = new FileInputStream(fileName);
             BufferedInputStream bis = new BufferedInputStream(fis)) {
            
            byte[] buffer = new byte[8192];
            int readBytes;
            while ((readBytes = bis.read(buffer)) != -1) {
                bytesRead += readBytes;
            }
        } catch (IOException e) {
            System.err.println("读取文件时发生错误: " + e.getMessage());
        }
        
        endTime = System.currentTimeMillis();
        long batchBufferTime = endTime - startTime;
        
        System.out.println("缓冲流批量读取:");
        System.out.println("  读取字节数: " + bytesRead);
        System.out.println("  耗时: " + batchBufferTime + " ms");
        System.out.println("  相比单字节读取提升: " + (bufferTime > 0 ? (double) bufferTime / batchBufferTime : "N/A") + " 倍");
    }
    
    // 缓冲字符流性能对比
    public static void characterStreamPerformanceComparison() {
        System.out.println("\n--- 缓冲字符流性能对比 ---");
        
        String fileName = "char_performance_test.txt";
        int lineCount = 100000; // 10万行数据
        
        // 创建测试数据
        try {
            createCharacterTestData(fileName, lineCount);
        } catch (IOException e) {
            System.err.println("创建字符测试数据时发生错误: " + e.getMessage());
            return;
        }
        
        // 不使用缓冲流逐行读取
        long startTime = System.currentTimeMillis();
        int linesRead = 0;
        
        try (FileReader fr = new FileReader(fileName, StandardCharsets.UTF_8)) {
            int character;
            StringBuilder line = new StringBuilder();
            while ((character = fr.read()) != -1) {
                if (character == '\n') {
                    linesRead++;
                    line.setLength(0); // 清空行缓冲
                } else {
                    line.append((char) character);
                }
            }
            // 处理最后一行(如果没有换行符)
            if (line.length() > 0) {
                linesRead++;
            }
        } catch (IOException e) {
            System.err.println("读取字符文件时发生错误: " + e.getMessage());
        }
        
        long endTime = System.currentTimeMillis();
        long noBufferTime = endTime - startTime;
        
        System.out.println("不使用缓冲流逐行读取:");
        System.out.println("  读取行数: " + linesRead);
        System.out.println("  耗时: " + noBufferTime + " ms");
        
        // 使用缓冲流逐行读取
        startTime = System.currentTimeMillis();
        linesRead = 0;
        
        try (FileReader fr = new FileReader(fileName, StandardCharsets.UTF_8);
             BufferedReader br = new BufferedReader(fr)) {
            
            String line;
            while ((line = br.readLine()) != null) {
                linesRead++;
            }
        } catch (IOException e) {
            System.err.println("读取字符文件时发生错误: " + e.getMessage());
        }
        
        endTime = System.currentTimeMillis();
        long bufferTime = endTime - startTime;
        
        System.out.println("使用缓冲流逐行读取:");
        System.out.println("  读取行数: " + linesRead);
        System.out.println("  耗时: " + bufferTime + " ms");
        System.out.println("  性能提升: " + (noBufferTime > 0 ? (double) noBufferTime / bufferTime : "N/A") + " 倍");
    }
    
    // 缓冲流的标记和重置功能
    public static void markAndResetExample() {
        System.out.println("\n--- 缓冲流的标记和重置功能 ---");
        
        String content = "这是第一行文本\n这是第二行文本\n这是第三行文本\n这是第四行文本\n这是第五行文本";
        
        try (StringReader sr = new StringReader(content);
             BufferedReader br = new BufferedReader(sr)) {
            
            // 读取第一行
            String line1 = br.readLine();
            System.out.println("读取第一行: " + line1);
            
            // 设置标记,缓冲区大小为1024
            br.mark(1024);
            
            // 读取接下来的两行
            String line2 = br.readLine();
            String line3 = br.readLine();
            System.out.println("读取第二行: " + line2);
            System.out.println("读取第三行: " + line3);
            
            // 重置到标记位置
            br.reset();
            System.out.println("重置后重新读取:");
            
            // 重新读取标记后的数据
            String resetLine2 = br.readLine();
            String resetLine3 = br.readLine();
            System.out.println("重新读取第二行: " + resetLine2);
            System.out.println("重新读取第三行: " + resetLine3);
            
            // 继续读取剩余行
            String line4 = br.readLine();
            String line5 = br.readLine();
            System.out.println("继续读取第四行: " + line4);
            System.out.println("继续读取第五行: " + line5);
            
        } catch (IOException e) {
            System.err.println("标记和重置操作时发生错误: " + e.getMessage());
        }
        
        // 演示标记失败的情况
        try (StringReader sr = new StringReader(content);
             BufferedReader br = new BufferedReader(sr, 16)) { // 小缓冲区
            
            String line1 = br.readLine();
            System.out.println("\n小缓冲区示例:");
            System.out.println("读取第一行: " + line1);
            
            // 设置标记
            br.mark(16);
            
            // 读取超过缓冲区大小的数据
            String line2 = br.readLine();
            String line3 = br.readLine();
            System.out.println("读取第二行: " + line2);
            System.out.println("读取第三行: " + line3);
            
            // 尝试重置(可能会失败)
            try {
                br.reset();
                System.out.println("重置成功");
            } catch (IOException e) {
                System.out.println("重置失败: " + e.getMessage());
                System.out.println("原因: 读取的数据超过了标记时指定的缓冲区大小");
            }
            
        } catch (IOException e) {
            System.err.println("小缓冲区示例时发生错误: " + e.getMessage());
        }
    }
    
    // 自定义缓冲区大小
    public static void customBufferSizeExample() {
        System.out.println("\n--- 自定义缓冲区大小 ---");
        
        String fileName = "custom_buffer_test.txt";
        
        // 创建测试文件
        try (FileWriter fw = new FileWriter(fileName, StandardCharsets.UTF_8);
             BufferedWriter bw = new BufferedWriter(fw, 64)) { // 64字节缓冲区
            
            for (int i = 1; i <= 100; i++) {
                bw.write("这是第" + i + "行测试数据");
                bw.newLine();
            }
            System.out.println("使用64字节缓冲区写入100行数据");
            
        } catch (IOException e) {
            System.err.println("写入文件时发生错误: " + e.getMessage());
        }
        
        // 测试不同缓冲区大小的性能
        testDifferentBufferSizes(fileName);
    }
    
    // 测试不同缓冲区大小的性能
    private static void testDifferentBufferSizes(String fileName) {
        System.out.println("\n不同缓冲区大小性能测试:");
        
        int[] bufferSizes = {16, 64, 256, 1024, 8192};
        
        for (int bufferSize : bufferSizes) {
            long startTime = System.currentTimeMillis();
            int linesRead = 0;
            
            try (FileReader fr = new FileReader(fileName, StandardCharsets.UTF_8);
                 BufferedReader br = new BufferedReader(fr, bufferSize)) {
                
                String line;
                while ((line = br.readLine()) != null) {
                    linesRead++;
                }
            } catch (IOException e) {
                System.err.println("读取文件时发生错误: " + e.getMessage());
                continue;
            }
            
            long endTime = System.currentTimeMillis();
            System.out.printf("缓冲区大小 %5d: 读取 %3d 行,耗时 %3d ms%n", 
                            bufferSize, linesRead, endTime - startTime);
        }
    }
    
    // 创建字节测试数据
    private static void createTestData(String fileName, int size) throws IOException {
        try (FileOutputStream fos = new FileOutputStream(fileName);
             BufferedOutputStream bos = new BufferedOutputStream(fos)) {
            
            byte[] data = new byte[size];
            for (int i = 0; i < size; i++) {
                data[i] = (byte) (i % 256);
            }
            bos.write(data);
        }
    }
    
    // 创建字符测试数据
    private static void createCharacterTestData(String fileName, int lineCount) throws IOException {
        try (FileWriter fw = new FileWriter(fileName, StandardCharsets.UTF_8);
             BufferedWriter bw = new BufferedWriter(fw)) {
            
            for (int i = 1; i <= lineCount; i++) {
                bw.write("这是第" + i + "行测试数据,包含一些中文字符和数字123456789");
                bw.newLine();
            }
        }
    }
}

转换流

转换流(InputStreamReader和OutputStreamWriter)用于在字节流和字符流之间进行转换,同时可以指定字符编码。

java
import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

// 转换流示例
public class StreamConverterExample {
    public static void main(String[] args) {
        System.out.println("=== 转换流示例 ===");
        
        // 1. 基本转换流使用
        basicConverterUsage();
        
        // 2. 字符编码转换
        charsetConversion();
        
        // 3. 系统默认编码处理
        systemDefaultEncoding();
        
        // 4. 转换流与缓冲流结合使用
        converterWithBuffer();
        
        // 5. 实用的编码检测和转换工具
        encodingUtility();
    }
    
    // 基本转换流使用
    public static void basicConverterUsage() {
        System.out.println("\n--- 基本转换流使用 ---");
        
        String text = "Hello 世界! 🌍\n这是一个转换流示例。\n支持Unicode字符。";
        
        // 使用OutputStreamWriter将字符转换为字节
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
             OutputStreamWriter osw = new OutputStreamWriter(baos, StandardCharsets.UTF_8)) {
            
            osw.write(text);
            osw.flush(); // 确保所有数据都被写出
            
            byte[] bytes = baos.toByteArray();
            System.out.println("原始文本: " + text);
            System.out.println("UTF-8编码字节数组长度: " + bytes.length);
            System.out.println("前20个字节: " + Arrays.toString(Arrays.copyOf(bytes, Math.min(20, bytes.length))));
            
            // 使用InputStreamReader将字节转换回字符
            try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
                 InputStreamReader isr = new InputStreamReader(bais, StandardCharsets.UTF_8)) {
                
                char[] buffer = new char[1024];
                int charsRead = isr.read(buffer);
                String decodedText = new String(buffer, 0, charsRead);
                
                System.out.println("解码后的文本: " + decodedText);
                System.out.println("文本是否相同: " + text.equals(decodedText));
            }
            
        } catch (IOException e) {
            System.err.println("转换流操作时发生错误: " + e.getMessage());
        }
    }
    
    // 字符编码转换
    public static void charsetConversion() {
        System.out.println("\n--- 字符编码转换 ---");
        
        String text = "Hello 世界! こんにちは! 안녕하세요!";
        
        // 不同编码的转换
        Charset[] charsets = {
            StandardCharsets.UTF_8,
            StandardCharsets.UTF_16,
            StandardCharsets.ISO_8859_1,
            Charset.forName("GBK")
        };
        
        System.out.println("原始文本: " + text);
        System.out.println("文本长度: " + text.length() + " 个字符");
        
        for (Charset charset : charsets) {
            try {
                // 编码为字节
                byte[] encodedBytes = text.getBytes(charset);
                
                // 解码回字符
                String decodedText = new String(encodedBytes, charset);
                
                System.out.printf("%-15s: %3d 字节, 解码正确: %s%n", 
                                charset.name(), 
                                encodedBytes.length, 
                                text.equals(decodedText));
                
                // 显示前几个字节(仅UTF-8)
                if (charset == StandardCharsets.UTF_8 && encodedBytes.length > 10) {
                    System.out.print("  前10个字节: ");
                    for (int i = 0; i < 10; i++) {
                        System.out.printf("%02X ", encodedBytes[i] & 0xFF);
                    }
                    System.out.println();
                }
                
            } catch (Exception e) {
                System.out.printf("%-15s: 不支持或转换失败%n", charset.name());
            }
        }
    }
    
    // 系统默认编码处理
    public static void systemDefaultEncoding() {
        System.out.println("\n--- 系统默认编码处理 ---");
        
        // 获取系统默认编码
        String defaultEncoding = System.getProperty("file.encoding");
        Charset defaultCharset = Charset.defaultCharset();
        
        System.out.println("JVM参数指定的编码: " + defaultEncoding);
        System.out.println("Java默认字符集: " + defaultCharset.name());
        System.out.println("可用字符集数量: " + Charset.availableCharsets().size());
        
        // 演示使用默认编码的问题
        String text = "中文测试文本";
        
        try {
            // 使用默认编码
            try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
                 OutputStreamWriter osw = new OutputStreamWriter(baos)) { // 使用默认编码
                
                osw.write(text);
                osw.flush();
                
                byte[] bytes = baos.toByteArray();
                System.out.println("\n使用默认编码 (" + osw.getEncoding() + "):");
                System.out.println("  原始文本: " + text);
                System.out.println("  字节数组: " + Arrays.toString(bytes));
                System.out.println("  字节长度: " + bytes.length);
                
                // 使用相同编码解码
                try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
                     InputStreamReader isr = new InputStreamReader(bais)) { // 使用默认编码
                    
                    char[] buffer = new char[1024];
                    int charsRead = isr.read(buffer);
                    String decoded = new String(buffer, 0, charsRead);
                    
                    System.out.println("  解码文本: " + decoded);
                    System.out.println("  编码一致: " + text.equals(decoded));
                }
            }
            
        } catch (IOException e) {
            System.err.println("默认编码处理时发生错误: " + e.getMessage());
        }
    }
    
    // 转换流与缓冲流结合使用
    public static void converterWithBuffer() {
        System.out.println("\n--- 转换流与缓冲流结合使用 ---");
        
        String fileName = "converter_buffer_test.txt";
        String content = "这是一个结合使用转换流和缓冲流的示例。\n" +
                        "通过这种方式可以提高I/O操作的效率。\n" +
                        "同时还能处理字符编码转换。\n" +
                        "适用于处理大量文本数据的场景。\n".repeat(100); // 重复100次
        
        // 写入文件 - 转换流 + 缓冲流
        long startTime = System.currentTimeMillis();
        
        try (FileOutputStream fos = new FileOutputStream(fileName);
             OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
             BufferedWriter bw = new BufferedWriter(osw)) {
            
            bw.write(content);
            bw.flush(); // 确保所有数据写出
            
        } catch (IOException e) {
            System.err.println("写入文件时发生错误: " + e.getMessage());
        }
        
        long writeTime = System.currentTimeMillis() - startTime;
        System.out.println("写入耗时: " + writeTime + " ms");
        System.out.println("写入字符数: " + content.length());
        
        // 读取文件 - 转换流 + 缓冲流
        startTime = System.currentTimeMillis();
        StringBuilder readContent = new StringBuilder();
        
        try (FileInputStream fis = new FileInputStream(fileName);
             InputStreamReader isr = new InputStreamReader(fis, StandardCharsets.UTF_8);
             BufferedReader br = new BufferedReader(isr)) {
            
            String line;
            while ((line = br.readLine()) != null) {
                readContent.append(line).append("\n");
            }
            
        } catch (IOException e) {
            System.err.println("读取文件时发生错误: " + e.getMessage());
        }
        
        long readTime = System.currentTimeMillis() - startTime;
        System.out.println("读取耗时: " + readTime + " ms");
        System.out.println("读取字符数: " + readContent.length());
        System.out.println("内容一致性: " + content.equals(readContent.toString()));
    }
    
    // 实用的编码检测和转换工具
    public static void encodingUtility() {
        System.out.println("\n--- 编码检测和转换工具 ---");
        
        // 创建不同编码的测试文件
        createTestFiles();
        
        // 检测和转换文件编码
        detectAndConvertEncoding();
    }
    
    // 创建不同编码的测试文件
    private static void createTestFiles() {
        String[] contents = {
            "UTF-8 encoded file with 中文 characters",
            "GBK encoded file with 中文 characters",
            "ASCII encoded file with English characters"
        };
        
        String[] encodings = {"UTF-8", "GBK", "US-ASCII"};
        String[] fileNames = {"utf8_test.txt", "gbk_test.txt", "ascii_test.txt"};
        
        for (int i = 0; i < contents.length; i++) {
            try (FileOutputStream fos = new FileOutputStream(fileNames[i]);
                 OutputStreamWriter osw = new OutputStreamWriter(fos, encodings[i])) {
                
                osw.write(contents[i]);
                System.out.println("创建 " + encodings[i] + " 编码文件: " + fileNames[i]);
                
            } catch (IOException e) {
                System.err.println("创建文件 " + fileNames[i] + " 时发生错误: " + e.getMessage());
            }
        }
    }
    
    // 检测和转换文件编码
    private static void detectAndConvertEncoding() {
        String[] fileNames = {"utf8_test.txt", "gbk_test.txt", "ascii_test.txt"};
        
        for (String fileName : fileNames) {
            System.out.println("\n检测文件: " + fileName);
            
            // 尝试用不同编码读取
            String[] encodings = {"UTF-8", "GBK", "US-ASCII", "ISO-8859-1"};
            
            for (String encoding : encodings) {
                try (FileInputStream fis = new FileInputStream(fileName);
                     InputStreamReader isr = new InputStreamReader(fis, encoding)) {
                    
                    char[] buffer = new char[1024];
                    int charsRead = isr.read(buffer);
                    String content = new String(buffer, 0, charsRead);
                    
                    // 简单的编码正确性检查
                    boolean isValid = true;
                    for (int i = 0; i < charsRead; i++) {
                        if (buffer[i] == 0xFFFD) { // Unicode替换字符
                            isValid = false;
                            break;
                        }
                    }
                    
                    System.out.printf("  %-10s: %s (有效: %s)%n", 
                                    encoding, 
                                    content.length() > 50 ? content.substring(0, 50) + "..." : content,
                                    isValid);
                    
                } catch (Exception e) {
                    System.out.printf("  %-10s: 读取失败 (%s)%n", encoding, e.getMessage());
                }
            }
        }
    }
}

// 高级转换流工具类
class AdvancedStreamConverter {
    // 智能编码检测
    public static Charset detectEncoding(File file) {
        // 常见编码列表
        Charset[] commonCharsets = {
            StandardCharsets.UTF_8,
            Charset.forName("GBK"),
            StandardCharsets.ISO_8859_1,
            StandardCharsets.US_ASCII
        };
        
        for (Charset charset : commonCharsets) {
            if (isValidEncoding(file, charset)) {
                return charset;
            }
        }
        
        return StandardCharsets.UTF_8; // 默认返回UTF-8
    }
    
    // 验证编码是否有效
    private static boolean isValidEncoding(File file, Charset charset) {
        try (FileInputStream fis = new FileInputStream(file);
             InputStreamReader isr = new InputStreamReader(fis, charset)) {
            
            char[] buffer = new char[1024];
            int charsRead = isr.read(buffer);
            
            // 检查是否包含无效字符
            for (int i = 0; i < charsRead; i++) {
                if (buffer[i] == 0xFFFD) { // Unicode替换字符
                    return false;
                }
            }
            
            return true;
        } catch (Exception e) {
            return false;
        }
    }
    
    // 转换文件编码
    public static void convertFileEncoding(File sourceFile, File targetFile, Charset targetCharset) 
            throws IOException {
        
        Charset sourceCharset = detectEncoding(sourceFile);
        
        try (FileInputStream fis = new FileInputStream(sourceFile);
             InputStreamReader isr = new InputStreamReader(fis, sourceCharset);
             BufferedReader br = new BufferedReader(isr);
             FileOutputStream fos = new FileOutputStream(targetFile);
             OutputStreamWriter osw = new OutputStreamWriter(fos, targetCharset);
             BufferedWriter bw = new BufferedWriter(osw)) {
            
            String line;
            while ((line = br.readLine()) != null) {
                bw.write(line);
                bw.newLine();
            }
        }
    }
    
    // 批量转换目录中的文件编码
    public static void convertDirectoryEncoding(File sourceDir, File targetDir, Charset targetCharset) 
            throws IOException {
        
        if (!targetDir.exists()) {
            targetDir.mkdirs();
        }
        
        File[] files = sourceDir.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isFile()) {
                    File targetFile = new File(targetDir, file.getName());
                    convertFileEncoding(file, targetFile, targetCharset);
                    System.out.println("转换文件: " + file.getName());
                } else if (file.isDirectory()) {
                    File targetSubDir = new File(targetDir, file.getName());
                    convertDirectoryEncoding(file, targetSubDir, targetCharset);
                }
            }
        }
    }
}

// 高级转换流工具使用示例
public class AdvancedConverterExample {
    public static void main(String[] args) {
        System.out.println("=== 高级转换流工具使用示例 ===");
        
        try {
            // 创建测试文件
            createTestFiles();
            
            // 智能编码检测
            smartEncodingDetection();
            
            // 文件编码转换
            fileEncodingConversion();
            
        } catch (IOException e) {
            System.err.println("高级转换流示例时发生错误: " + e.getMessage());
        }
    }
    
    private static void createTestFiles() throws IOException {
        System.out.println("\n--- 创建测试文件 ---");
        
        // 创建UTF-8编码文件
        try (FileWriter fw = new FileWriter("test_utf8.txt", StandardCharsets.UTF_8)) {
            fw.write("UTF-8测试文件\n包含中文字符:你好世界\nEnglish text with special characters: €£¥");
        }
        
        // 创建GBK编码文件
        try (OutputStreamWriter osw = new OutputStreamWriter(
                new FileOutputStream("test_gbk.txt"), "GBK")) {
            osw.write("GBK测试文件\n包含中文字符:你好世界\nEnglish text");
        }
        
        System.out.println("测试文件创建完成");
    }
    
    private static void smartEncodingDetection() {
        System.out.println("\n--- 智能编码检测 ---");
        
        String[] testFiles = {"test_utf8.txt", "test_gbk.txt"};
        
        for (String fileName : testFiles) {
            File file = new File(fileName);
            if (file.exists()) {
                Charset detectedCharset = AdvancedStreamConverter.detectEncoding(file);
                System.out.println("文件 " + fileName + " 检测到的编码: " + detectedCharset.name());
            }
        }
    }
    
    private static void fileEncodingConversion() throws IOException {
        System.out.println("\n--- 文件编码转换 ---");
        
        File sourceFile = new File("test_utf8.txt");
        File targetFile = new File("converted_to_gbk.txt");
        
        if (sourceFile.exists()) {
            AdvancedStreamConverter.convertFileEncoding(
                sourceFile, targetFile, Charset.forName("GBK"));
            System.out.println("文件编码转换完成: " + sourceFile.getName() + " -> " + targetFile.getName());
            
            // 验证转换结果
            Charset detectedCharset = AdvancedStreamConverter.detectEncoding(targetFile);
            System.out.println("转换后文件编码: " + detectedCharset.name());
        }
    }
}

通过本章节的学习,您已经掌握了Java I/O流的核心概念和使用方法,包括字节流与字符流的区别、文件操作、缓冲流和转换流的应用。这些知识是Java程序处理数据输入输出的基础,对于开发各种Java应用程序都非常重要。