java读写复制

admin 104 0
Java文件读写复制主要通过IO流和NIO实现,字节流(FileInputStream/FileOutputStream)适合二进制文件操作,字符流(FileReader/FileWriter)处理文本数据,BufferedInputStream/OutputStream通过缓冲区提升读写效率,NIO的Files.copy()方法更简洁,利用通道(Channel)和缓冲区(Buffer)优化性能,适合大文件操作,需注意异常处理(如FileNotFoundException、IOException),确保资源关闭(try-with-resources),复制时可根据需求选择流式逐块读写或直接文件拷贝,兼顾功能与效率。

Java文件读写与复制操作详解:从基础到实践

在Java开发中,文件读写与复制操作是最基础也是最常用的功能之一,无论是处理配置文件、日志数据,还是实现文件上传下载功能,都离不开对文件流的操作,本文将从Java IO的核心类入手,逐步介绍字节流、字符流的使用方法,并对比传统IO与NIO(New I/O)的复制技术,最后结合最佳实践帮助读者掌握高效、安全的文件操作技巧。

Java文件读写的核心:IO流基础

Java的IO操作通过"流"(Stream)这一抽象概念实现,流是数据的有序序列,按照处理数据类型可分为字节流(处理二进制文件,如图片、视频)和字符流(处理文本文件,如.txt、.csv),字节流以字节(byte)为单位进行操作,字符流以字符(char)为单位,底层均基于字节流并通过字符编码进行转换。

字节流:InputStream与OutputStream

字节流是IO操作的基础,核心类包括InputStream(输入流,用于读取数据)和OutputStream(输出流,用于写入数据)。

读取文件

使用FileInputStream读取文件,通过read()方法可以逐字节或批量读取数据:

try (FileInputStream fis = new FileInputStream("input.txt")) {
    byte[] buffer = new byte[1024]; // 8KB缓冲区
    int bytesRead;
    while ((bytesRead = fis.read(buffer)) != -1) {
        // 处理读取的字节数据(如写入输出流或转换为字符串)
        System.out.write(buffer, 0, bytesRead);
    }
} catch (IOException e) {
    // 建议使用日志记录而非直接打印堆栈
    logger.error("文件读取失败", e);
}

注意:使用try-with-resources语法可以自动关闭流资源,避免资源泄漏。

写入文件

使用FileOutputStream写入文件,通过write()方法将字节写入目标文件:

try (FileOutputStream fos = new FileOutputStream("output.txt")) {
    String content = "Hello, Java IO!";
    fos.write(content.getBytes(StandardCharsets.UTF_8)); // 指定编码写入
} catch (IOException e) {
    logger.error("文件写入失败", e);
}

字符流:Reader与Writer

字符流专门处理文本数据,通过指定字符编码(如UTF-8)可以有效避免乱码问题,核心类包括Reader(输入字符流)和Writer(输出字符流)。

读取文本文件

使用FileReader读取文本文件,结合BufferedReader可以显著提高读取效率:

try (BufferedReader reader = new BufferedReader(
        new InputStreamReader(new FileInputStream("input.txt"), StandardCharsets.UTF_8))) {
    String line;
    while ((line = reader.readLine()) != null) {
        System.out.println(line); // 逐行读取
    }
} catch (IOException e) {
    logger.error("文本文件读取失败", e);
}
写入文本文件

使用FileWriter写入文本文件,建议结合BufferedWriter进行缓冲写入:

try (BufferedWriter writer = new BufferedWriter(
        new OutputStreamWriter(new FileOutputStream("output.txt"), StandardCharsets.UTF_8))) {
    writer.write("Hello, Java Character Stream!");
    writer.newLine(); // 写入跨平台兼容的换行符
} catch (IOException e) {
    logger.error("文本文件写入失败", e);
}

缓冲流:提升IO性能

直接使用字节流/字符流逐个读写数据效率较低,Java提供了缓冲流(BufferedInputStreamBufferedOutputStreamBufferedReaderBufferedWriter)通过缓冲区机制减少磁盘IO次数,大幅提升性能。

缓冲流的工作原理是:读取时一次性从磁盘读取一批数据到内存缓冲区,后续操作直接从内存读取;写入时先写入内存缓冲区,缓冲区满或刷新时才写入磁盘,这种批量处理方式显著减少了磁盘访问次数,对于大文件操作尤为明显。

文件复制操作的多种实现

文件复制本质上是一个"读取源文件 + 写入目标文件"的组合操作,根据不同的应用场景,可以通过传统IO、NIO或第三方库实现多种复制策略。

传统IO方式:字节流逐复制

通过FileInputStream读取源文件,用FileOutputStream写入目标文件,适合小文件复制:

public void copyWithIO(String source, String target) {
    try (InputStream in = new FileInputStream(source);
         OutputStream out = new FileOutputStream(target)) {
        byte[] buffer = new byte[8192]; // 8KB缓冲区
        int length;
        while ((length = in.read(buffer)) > 0) {
            out.write(buffer, 0, length);
        }
    } catch (IOException e) {
        logger.error("文件复制失败", e);
    }
}

特点:实现简单直观,代码可读性强,但大文件复制时可能因频繁IO操作性能较低,测试表明,对于100MB文件,传统IO方式通常需要200-300毫秒。

NIO方式:高效文件复制

Java NIO(New I/O)从Java 1.4引入,通过Channel(通道)和Buffer(缓冲区)实现非阻塞IO,更适合大文件和高并发场景,核心类包括Path(文件路径)、Files(文件操作工具类)、FileChannel(文件通道)。

方法1:Files.copy()(最简单)

Files类提供了静态方法copy(),支持多种复制选项(如覆盖、替换):

import java.nio.file.*;
public void copyWithNIO(String source, String target) {
    try {
        Path sourcePath = Paths.get(source);
        Path targetPath = Paths.get(target);
        // 复制文件(覆盖目标文件,如果存在)
        Files.copy(sourcePath, targetPath, 
                  StandardCopyOption.REPLACE_EXISTING,
                  StandardCopyOption.COPY_ATTRIBUTES);
    } catch (IOException e) {
        logger.error("NIO文件复制失败", e);
    }
}

特点:代码简洁,底层通过系统调用优化,适合大多数场景,对于100MB文件,Files.copy()通常只需50-100毫秒,性能提升显著。

方法2:FileChannel(可控性更强)

通过FileChannel可以实现更精细的控制,如支持直接内存映射:

public void copyWithFileChannel(String source, String target) throws IOException {
    try (FileChannel sourceChannel = FileChannel.open(Paths.get(source), 
                                                   StandardOpenOption.READ);
         FileChannel targetChannel = FileChannel.open(Paths.get(target), 
                                                   StandardOpenOption.WRITE,
                                                   StandardOpenOption.CREATE)) {
        // 使用transferTo方法进行高效传输
        long position = 0;
        long count = sourceChannel.size();
        while (count > 0) {
            long transferred = sourceChannel.transferTo(position, count, targetChannel);
            position += transferred;
            count -= transferred;
        }
    }
}

特点:性能最优,特别是对于超大文件(GB级别),FileChanneltransferTo方法可以利用操作系统零拷贝机制,避免数据在用户空间和内核空间之间的不必要拷贝。

第三方库方式:Apache Commons IO

对于需要更高抽象层次和更多功能的场景,可以使用Apache Commons IO库:

import org.apache.commons.io.FileUtils;
public void copyWithCommonsIO(String source, String target) throws IOException {
    File sourceFile = new File(source);
    File targetFile = new File(target);
    FileUtils.copyFile(sourceFile, targetFile);
}

特点

标签: #java #读写