你能否用Java的IO流编写一个文件复制工具

wen java案例 51

当然可以!这里提供一个实用的Java文件复制工具类,包含多种复制方式和详细的代码注释:

你能否用Java的IO流编写一个文件复制工具

import java.io.*;
import java.nio.channels.FileChannel;
import java.nio.file.*;
/**
 * 文件复制工具类
 * 包含多种文件复制方式:字节流、字符流、NIO通道等
 */
public class FileCopyTool {
    /**
     * 使用传统字节流复制文件(基础版)
     * @param source 源文件路径
     * @param target 目标文件路径
     * @throws IOException IO异常
     */
    public static void copyByStream(String source, String target) throws IOException {
        // 验证源文件是否存在
        File sourceFile = new File(source);
        if (!sourceFile.exists()) {
            throw new FileNotFoundException("源文件不存在: " + source);
        }
        // 确保目标目录存在
        File targetFile = new File(target);
        File parentDir = targetFile.getParentFile();
        if (parentDir != null && !parentDir.exists()) {
            parentDir.mkdirs();
        }
        // 使用try-with-resources自动关闭资源
        try (FileInputStream fis = new FileInputStream(sourceFile);
             FileOutputStream fos = new FileOutputStream(targetFile);
             BufferedInputStream bis = new BufferedInputStream(fis);
             BufferedOutputStream bos = new BufferedOutputStream(fos)) {
            byte[] buffer = new byte[8192]; // 8KB缓冲区
            int bytesRead;
            // 循环读取并写入
            while ((bytesRead = bis.read(buffer)) != -1) {
                bos.write(buffer, 0, bytesRead);
            }
            bos.flush(); // 强制刷新缓冲区
        }
    }
    /**
     * 使用NIO FileChannel复制文件(推荐用于大文件)
     * @param source 源文件路径
     * @param target 目标文件路径
     * @throws IOException IO异常
     */
    public static void copyByChannel(String source, String target) throws IOException {
        Path sourcePath = Paths.get(source);
        Path targetPath = Paths.get(target);
        // 确保目标目录存在
        Files.createDirectories(targetPath.getParent());
        // 使用FileChannel进行高效的零拷贝传输
        try (FileChannel sourceChannel = FileChannel.open(sourcePath, StandardOpenOption.READ);
             FileChannel targetChannel = FileChannel.open(targetPath, 
                     StandardOpenOption.CREATE, StandardOpenOption.WRITE)) {
            long position = 0;
            long size = sourceChannel.size();
            // 使用transferTo实现零拷贝,减少数据在内核和用户空间之间的拷贝
            while (position < size) {
                position += sourceChannel.transferTo(position, size - position, targetChannel);
            }
        }
    }
    /**
     * 使用NIO Files工具类复制(最简单方式)
     * @param source 源文件路径
     * @param target 目标文件路径
     * @param replaceExisting 是否覆盖已存在的文件
     * @throws IOException IO异常
     */
    public static void copyByFiles(String source, String target, boolean replaceExisting) throws IOException {
        Path sourcePath = Paths.get(source);
        Path targetPath = Paths.get(target);
        // 创建目标目录
        Files.createDirectories(targetPath.getParent());
        // 复制选项
        CopyOption[] options = replaceExisting 
                ? new CopyOption[] { StandardCopyOption.REPLACE_EXISTING }
                : new CopyOption[] {};
        // 使用Files.copy()方法
        Files.copy(sourcePath, targetPath, options);
    }
    /**
     * 带进度显示的文件复制(使用字节流)
     * @param source 源文件路径
     * @param target 目标文件路径
     * @throws IOException IO异常
     */
    public static void copyWithProgress(String source, String target) throws IOException {
        File sourceFile = new File(source);
        if (!sourceFile.exists()) {
            throw new FileNotFoundException("源文件不存在: " + source);
        }
        long totalBytes = sourceFile.length();
        long copiedBytes = 0;
        // 确保目标目录存在
        File targetFile = new File(target);
        File parentDir = targetFile.getParentFile();
        if (parentDir != null && !parentDir.exists()) {
            parentDir.mkdirs();
        }
        try (FileInputStream fis = new FileInputStream(sourceFile);
             FileOutputStream fos = new FileOutputStream(targetFile);
             BufferedInputStream bis = new BufferedInputStream(fis);
             BufferedOutputStream bos = new BufferedOutputStream(fos)) {
            byte[] buffer = new byte[8192];
            int bytesRead;
            int progress = 0;
            int lastProgress = 0;
            System.out.print("复制进度: ");
            while ((bytesRead = bis.read(buffer)) != -1) {
                bos.write(buffer, 0, bytesRead);
                copiedBytes += bytesRead;
                // 计算并显示进度
                progress = (int) (copiedBytes * 100 / totalBytes);
                if (progress > lastProgress) {
                    System.out.print("\r复制进度: " + progress + "%");
                    lastProgress = progress;
                }
            }
            bos.flush();
            System.out.println("\r复制进度: 100% - 完成!");
        }
    }
    /**
     * 递归复制目录
     * @param sourceDir 源目录路径
     * @param targetDir 目标目录路径
     * @throws IOException IO异常
     */
    public static void copyDirectory(String sourceDir, String targetDir) throws IOException {
        File source = new File(sourceDir);
        File target = new File(targetDir);
        if (!source.exists()) {
            throw new FileNotFoundException("源目录不存在: " + sourceDir);
        }
        if (!source.isDirectory()) {
            throw new IllegalArgumentException("源路径必须是目录: " + sourceDir);
        }
        // 创建目标目录
        if (!target.exists()) {
            target.mkdirs();
        }
        // 获取源目录下的所有文件
        File[] files = source.listFiles();
        if (files == null) {
            throw new IOException("无法读取目录: " + sourceDir);
        }
        for (File file : files) {
            String targetPath = targetDir + File.separator + file.getName();
            if (file.isDirectory()) {
                // 递归复制子目录
                copyDirectory(file.getAbsolutePath(), targetPath);
            } else {
                // 复制文件
                copyByStream(file.getAbsolutePath(), targetPath);
            }
        }
    }
    /**
     * 主方法 - 演示使用
     */
    public static void main(String[] args) {
        try {
            // 测试文件复制
            String sourceFile = "test.txt";
            String targetFile = "test_copy.txt";
            // 创建测试文件
            try (FileWriter writer = new FileWriter(sourceFile)) {
                writer.write("Hello, File Copy Tool!\n");
                writer.write("This is a test file.\n");
                writer.write("包含中文字符测试。\n");
            }
            System.out.println("=== 字节流复制 ===");
            copyByStream(sourceFile, "test_stream_copy.txt");
            System.out.println("\n=== NIO Channel复制 ===");
            copyByChannel(sourceFile, "test_channel_copy.txt");
            System.out.println("\n=== Files工具类复制 ===");
            copyByFiles(sourceFile, "test_files_copy.txt", true);
            System.out.println("\n=== 带进度复制 ===");
            copyWithProgress(sourceFile, "test_progress_copy.txt");
            System.out.println("\n=== 测试目录复制 ===");
            // 创建测试目录
            new File("testDir").mkdirs();
            try (FileWriter writer = new FileWriter("testDir/test1.txt")) {
                writer.write("File 1 content");
            }
            try (FileWriter writer = new FileWriter("testDir/test2.txt")) {
                writer.write("File 2 content");
            }
            copyDirectory("testDir", "testDir_copy");
            System.out.println("所有复制操作完成!");
        } catch (IOException e) {
            System.err.println("复制失败: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

主要功能特点:

  1. 多种复制方式

    • 传统字节流复制
    • NIO Channel零拷贝复制(适合大文件)
    • Files工具类简单复制
  2. 高级功能

    • 支持进度显示
    • 递归复制整个目录
    • 自动创建目标目录结构
  3. 最佳实践

    • 使用缓冲流提高性能
    • try-with-resources自动资源管理
    • 合理的缓冲区大小(8KB)
    • 完善的异常处理

使用建议:

  • 大文件推荐使用 copyByChannel() 的零拷贝方式
  • 简单场景使用 copyByFiles() 最方便
  • 需要进度显示时使用 copyWithProgress()
  • 复制目录使用 copyDirectory()

抱歉,评论功能暂时关闭!