小熊奶糖(BearCandy)
小熊奶糖(BearCandy)
发布于 2025-10-14 / 0 阅读
0
0

Java IO 数据流(数据和流转)和缓存

一、Java IO 文件流

1. 文件流基础概念

文件流是用于读写文件数据的流,主要分为字节流和字符流。

字节流类体系

InputStream (抽象类)
├── FileInputStream (文件字节输入流)
├── FilterInputStream
└── ObjectInputStream

OutputStream (抽象类)
├── FileOutputStream (文件字节输出流)
├── FilterOutputStream
└── ObjectOutputStream

字符流类体系

Reader (抽象类)
├── FileReader (文件字符输入流)
├── BufferedReader
└── InputStreamReader

Writer (抽象类)
├── FileWriter (文件字符输出流)
├── BufferedWriter
└── OutputStreamWriter

2. 文件字节流示例

import java.io.*;

public class FileStreamExample {
  
    // 使用 FileInputStream 和 FileOutputStream
    public static void byteStreamExample() {
        String sourceFile = "source.txt";
        String targetFile = "target.txt";
      
        try (FileInputStream fis = new FileInputStream(sourceFile);
             FileOutputStream fos = new FileOutputStream(targetFile)) {
          
            byte[] buffer = new byte[1024];
            int bytesRead;
          
            while ((bytesRead = fis.read(buffer)) != -1) {
                fos.write(buffer, 0, bytesRead);
            }
          
            System.out.println("文件复制完成");
          
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  
    // 读取文件内容到字符串
    public static String readFileToString(String filename) {
        try (FileInputStream fis = new FileInputStream(filename)) {
            byte[] data = new byte[fis.available()];
            fis.read(data);
            return new String(data);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
}

3. 文件字符流示例

import java.io.*;

public class CharacterStreamExample {
  
    // 使用 FileReader 和 FileWriter
    public static void characterStreamExample() {
        String sourceFile = "source.txt";
        String targetFile = "target.txt";
      
        try (FileReader reader = new FileReader(sourceFile);
             FileWriter writer = new FileWriter(targetFile)) {
          
            char[] buffer = new char[1024];
            int charsRead;
          
            while ((charsRead = reader.read(buffer)) != -1) {
                writer.write(buffer, 0, charsRead);
            }
          
            System.out.println("字符流文件复制完成");
          
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  
    // 逐行读取文本文件
    public static void readFileLineByLine(String filename) {
        try (FileReader fr = new FileReader(filename);
             BufferedReader br = new BufferedReader(fr)) {
          
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
          
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

二、Java IO 缓冲

1. 缓冲流的作用

缓冲流通过在内存中创建缓冲区来提高 IO 效率:

  • 减少实际的物理读写次数
  • 批量处理数据,提高性能
  • 提供额外的便捷方法

2. 缓冲字节流

import java.io.*;

public class BufferedStreamExample {
  
    // 使用 BufferedInputStream 和 BufferedOutputStream
    public static void bufferedByteStream() {
        String sourceFile = "largefile.dat";
        String targetFile = "copy.dat";
      
        try (FileInputStream fis = new FileInputStream(sourceFile);
             BufferedInputStream bis = new BufferedInputStream(fis);
             FileOutputStream fos = new FileOutputStream(targetFile);
             BufferedOutputStream bos = new BufferedOutputStream(fos)) {
          
            byte[] buffer = new byte[8192]; // 8KB 缓冲区
            int bytesRead;
          
            long startTime = System.currentTimeMillis();
          
            while ((bytesRead = bis.read(buffer)) != -1) {
                bos.write(buffer, 0, bytesRead);
            }
          
            long endTime = System.currentTimeMillis();
            System.out.println("缓冲流复制耗时: " + (endTime - startTime) + "ms");
          
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  
    // 比较有缓冲和无缓冲的性能差异
    public static void comparePerformance() {
        String testFile = "testfile.dat";
        createTestFile(testFile, 100 * 1024 * 1024); // 创建 100MB 测试文件
      
        // 无缓冲复制
        long start1 = System.currentTimeMillis();
        copyWithoutBuffer(testFile, "without_buffer.dat");
        long end1 = System.currentTimeMillis();
      
        // 有缓冲复制
        long start2 = System.currentTimeMillis();
        copyWithBuffer(testFile, "with_buffer.dat");
        long end2 = System.currentTimeMillis();
      
        System.out.println("无缓冲复制耗时: " + (end1 - start1) + "ms");
        System.out.println("有缓冲复制耗时: " + (end2 - start2) + "ms");
    }
  
    private static void createTestFile(String filename, long size) {
        try (RandomAccessFile raf = new RandomAccessFile(filename, "rw")) {
            raf.setLength(size);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  
    private static void copyWithoutBuffer(String source, String target) {
        try (FileInputStream fis = new FileInputStream(source);
             FileOutputStream fos = new FileOutputStream(target)) {
          
            int data;
            while ((data = fis.read()) != -1) { // 逐字节读取,性能较差
                fos.write(data);
            }
          
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  
    private static void copyWithBuffer(String source, String target) {
        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(source));
             BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(target))) {
          
            byte[] buffer = new byte[8192];
            int bytesRead;
            while ((bytesRead = bis.read(buffer)) != -1) {
                bos.write(buffer, 0, bytesRead);
            }
          
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

3. 缓冲字符流

import java.io.*;

public class BufferedCharacterStream {
  
    // 使用 BufferedReader 和 BufferedWriter
    public static void bufferedCharacterExample() {
        String inputFile = "input.txt";
        String outputFile = "output.txt";
      
        try (BufferedReader reader = new BufferedReader(new FileReader(inputFile));
             BufferedWriter writer = new BufferedWriter(new FileWriter(outputFile))) {
          
            String line;
            while ((line = reader.readLine()) != null) {
                // 处理每一行数据
                String processedLine = processLine(line);
                writer.write(processedLine);
                writer.newLine(); // 写入换行符
            }
          
            System.out.println("文件处理完成");
          
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  
    private static String processLine(String line) {
        // 示例处理逻辑:转换为大写并添加前缀
        return "PROCESSED: " + line.toUpperCase();
    }
  
    // 使用 mark() 和 reset() 方法
    public static void markResetExample() {
        String text = "Hello World! This is a test.";
      
        try (BufferedReader reader = new BufferedReader(new StringReader(text))) {
          
            // 标记当前位置
            reader.mark(100);
          
            // 读取前5个字符
            char[] buffer = new char[5];
            reader.read(buffer);
            System.out.println("第一次读取: " + new String(buffer));
          
            // 重置到标记位置
            reader.reset();
          
            // 再次读取
            reader.read(buffer);
            System.out.println("重置后读取: " + new String(buffer));
          
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

4. 缓冲流的实用方法

import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class BufferedStreamUtilities {
  
    // 读取文件所有行到列表
    public static List<String> readAllLines(String filename) {
        List<String> lines = new ArrayList<>();
      
        try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
            String line;
            while ((line = reader.readLine()) != null) {
                lines.add(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
      
        return lines;
    }
  
    // 批量写入行到文件
    public static void writeLines(List<String> lines, String filename) {
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(filename))) {
            for (String line : lines) {
                writer.write(line);
                writer.newLine();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  
    // 使用 PrintWriter 进行格式化输出
    public static void printWriterExample() {
        try (PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter("output.txt")))) {
            pw.printf("姓名: %s, 年龄: %d%n", "张三", 25);
            pw.println("这是一行文本");
            pw.format("当前时间: %tF %tT%n", System.currentTimeMillis(), System.currentTimeMillis());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

5. 综合示例:文件加密工具

import java.io.*;

public class FileEncryptionTool {
  
    // 使用缓冲流进行文件加密/解密
    public static void encryptFile(String sourceFile, String targetFile, int key) {
        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sourceFile));
             BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(targetFile))) {
          
            int data;
            while ((data = bis.read()) != -1) {
                // 简单的异或加密
                bos.write(data ^ key);
            }
          
            System.out.println("文件加密完成");
          
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  
    // 解密文件(加密的逆过程)
    public static void decryptFile(String encryptedFile, String decryptedFile, int key) {
        encryptFile(encryptedFile, decryptedFile, key); // 异或加密的解密是同样的操作
        System.out.println("文件解密完成");
    }
  
    // 带进度显示的文件复制
    public static void copyWithProgress(String source, String target) {
        File sourceFile = new File(source);
        long totalBytes = sourceFile.length();
        long copiedBytes = 0;
      
        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(source));
             BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(target))) {
          
            byte[] buffer = new byte[8192];
            int bytesRead;
          
            while ((bytesRead = bis.read(buffer)) != -1) {
                bos.write(buffer, 0, bytesRead);
                copiedBytes += bytesRead;
              
                // 显示进度
                int progress = (int) ((copiedBytes * 100) / totalBytes);
                System.out.printf("\r复制进度: %d%% [%d/%d bytes]", 
                    progress, copiedBytes, totalBytes);
            }
          
            System.out.println("\n文件复制完成");
          
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

三、最佳实践和注意事项

1. 资源管理

// 推荐使用 try-with-resources
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
    // 使用资源
} catch (IOException e) {
    // 异常处理
}

// 不推荐的方式(需要手动关闭)
BufferedReader reader = null;
try {
    reader = new BufferedReader(new FileReader("file.txt"));
    // 使用资源
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (reader != null) {
        try {
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2. 缓冲区大小选择

public class BufferSizeRecommendation {
    // 常见的缓冲区大小
    private static final int[] BUFFER_SIZES = {
        1024,     // 1KB - 小文件
        8192,     // 8KB - 通用
        32768,    // 32KB - 大文件
        65536     // 64KB - 超大文件
    };
  
    public static int getOptimalBufferSize(long fileSize) {
        if (fileSize < 1024 * 1024) {        // < 1MB
            return BUFFER_SIZES[0];
        } else if (fileSize < 10 * 1024 * 1024) { // < 10MB
            return BUFFER_SIZES[1];
        } else if (fileSize < 100 * 1024 * 1024) { // < 100MB
            return BUFFER_SIZES[2];
        } else {
            return BUFFER_SIZES[3];
        }
    }
}

总结

  1. 文件流:提供了基本的文件读写能力,分为字节流和字符流
  2. 缓冲流:通过内存缓冲区提高 IO 性能,减少物理读写次数
  3. 性能优化:合理选择缓冲区大小,使用 try-with-resources 管理资源
  4. 适用场景
    • 文本文件处理:使用字符缓冲流
    • 二进制文件:使用字节缓冲流
    • 大文件操作:必须使用缓冲流
    • 逐行处理:使用 BufferedReader 的 readLine() 方法

掌握这些概念和方法能够帮助你编写更高效、更健壮的 Java IO 程序。


评论