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提供了缓冲流(BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter)通过缓冲区机制减少磁盘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级别),FileChannel的transferTo方法可以利用操作系统零拷贝机制,避免数据在用户空间和内核空间之间的不必要拷贝。
第三方库方式: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);
}
特点