Java实战:复制文件的4 种方法

Java实战:复制文件的4 种方法

“复制文件看似简单,却是展示代码功底的好机会!” 🎯 无论是期末作业、毕业设计,还是项目开发,本文带你全面掌握 Java 文件复制的 4 种方法:经典的流(Stream)、高效的 FileChannel、便捷的 Apache Commons IO,以及现代化的 Files 类,外加 1GB 文件性能对比,帮你选出最快、最适合的方案!💡 阅读后别忘了 点赞 👍、收藏 ⭐、关注 👀、分享 🔗,一起提升 Java 技能,让你的代码更出彩、更高效!✨。如果你有更好的方法,欢迎在评论区留言,有任何疑问也可以私信作者,给你解答。

Java 文件复制是一个非常常见的操作。但是 java.io.File 类并没有提供从源文件复制到目标文件的快捷方法。本文中介绍在 Java 中实现文件复制的四种不同方式。

一.使用流(Stream)复制文件

这是在 Java 中实现文件复制的传统方式。在这种方法中,我们创建两个文件对象——源文件(source)和目标文件(destination)。然后,我们从源文件创建输入流(InputStream),并通过输出流(OutputStream)将数据写入目标文件。

以下是使用流(Stream)实现文件复制的方法代码

// 使用流(Stream)复制文件的方法

private static void copyFileUsingStream(File source, File dest) throws IOException {

InputStream is = null; // 定义输入流对象,用于从源文件中读取数据

OutputStream os = null; // 定义输出流对象,用于将数据写入目标文件

try {

// 创建输入流,指向源文件

is = new FileInputStream(source);

// 创建输出流,指向目标文件

os = new FileOutputStream(dest);

// 定义一个字节缓冲区,用于临时存储读取的数据,大小为 1024 字节

byte[] buffer = new byte[1024];

int length; // 定义变量,用于存储每次读取的字节数

// 循环读取源文件的数据,直到文件结束(read() 返回 -1)

while ((length = is.read(buffer)) > 0) {

// 将读取的数据写入目标文件,从缓冲区的起始位置开始写入,写入长度为读取的字节数

os.write(buffer, 0, length);

}

} finally {

// 关闭输入流,释放资源

if (is != null) {

is.close();

}

// 关闭输出流,释放资源

if (os != null) {

os.close();

}

}

}

1.1.方法说明

输入流和输出流:通过 FileInputStream 和 FileOutputStream 创建输入和输出流,用于读取源文件和写入目标文件。缓冲区:byte[] buffer 用于临时存储从源文件中读取的数据,避免频繁操作文件,提高效率。循环读取与写入:通过 is.read(buffer) 方法从源文件中读取数据,并通过 os.write(buffer, 0, length) 将数据写入目标文件。关闭资源:在 finally 块中关闭流,以确保无论是否发生异常,资源都会被正确释放。1.2.注意事项

异常处理:代码中使用了 try-finally 块来确保资源的正确释放。缓冲区大小:缓冲区大小可以根据文件大小和性能需求进行调整,以提高效率。

二.使用java.nio.channels.FileChannel实现文件复制

Java NIO 类是在 Java 1.4 中引入的,其中 FileChannel 可用于在 Java 中复制文件。根据 javadoc中transferFrom() 方法的介绍,这种文件复制方法的速度通常比使用流(Streams)更快。

以下是使用 FileChannel 复制文件的方法实现。

// 使用 FileChannel 实现文件复制

private static void copyFileUsingChannel(File source, File dest) throws IOException {

FileChannel sourceChannel = null; // 定义源文件的 FileChannel

FileChannel destChannel = null; // 定义目标文件的 FileChannel

try {

// 创建源文件的 FileChannel,使用 FileInputStream 打开源文件

sourceChannel = new FileInputStream(source).getChannel();

// 创建目标文件的 FileChannel,使用 FileOutputStream 打开目标文件

destChannel = new FileOutputStream(dest).getChannel();

// 使用 FileChannel 的 transferFrom 方法从源文件复制内容到目标文件

// 参数 0 表示从文件的开头开始复制

// sourceChannel.size() 获取源文件的总大小(字节数)

destChannel.transferFrom(sourceChannel, 0, sourceChannel.size());

} finally {

// 关闭源文件的 FileChannel,释放资源

if (sourceChannel != null) sourceChannel.close();

// 关闭目标文件的 FileChannel,释放资源

if (destChannel != null) destChannel.close();

}

}

2.1.方法说明:

FileChannel:

是 java.nio 包中用于文件读写的通道类。它支持文件的高效读写,尤其适合处理大文件。

transferFrom() 方法:

这是 FileChannel 提供的一个方法,用于从一个通道(sourceChannel)复制内容到当前通道(destChannel)。参数说明:

第一个参数:源文件的通道对象。第二个参数:目标文件中写入数据的起始位置。第三个参数:需要复制的字节数。

代码关键点:

在 try 块中初始化资源,并在 finally 块中确保释放资源(关闭通道)。使用 FileInputStream 和 FileOutputStream 创建文件输入流和输出流,并从中获取 FileChannel。通过这种方式复制文件,效率较高,适合处理大文件,但具体性能提升与文件大小和硬件配置有关。

三.使用 Apache Commons IO 的 FileUtils 进行文件复制

Apache Commons IO 提供了一个简单的工具方法 FileUtils.copyFile(File srcFile, File destFile) 来实现文件复制。如果你的项目中已经引入了 Apache Commons IO 库,使用它可以使代码更简单明了。

注意:FileUtils.copyFile 方法内部使用了 Java NIO 的 FileChannel,因此如果你的项目中没有其他功能依赖 Apache Commons IO,可以直接使用 FileChannel 而没有必要单独引入Apache Commons IO库

以下是使用 Apache Commons IO 进行文件复制的代码示例:

// 使用 Apache Commons IO 的 FileUtils 方法实现文件复制

private static void copyFileUsingApacheCommonsIO(File source, File dest) throws IOException {

// 使用 FileUtils.copyFile 方法将源文件复制到目标文件

FileUtils.copyFile(source, dest);

}

3.1.方法说明:

File source:表示源文件对象。File dest:表示目标文件对象。FileUtils.copyFile():Apache Commons IO 提供的静态方法,用于文件复制操作。优点:

代码简单,易于理解。如果项目已经依赖 Apache Commons IO,使用该方法是一个方便的选择。内部基于 Java NIO 的 FileChannel,具有较高的性能。缺点:

如果项目中没有其他功能需要 Apache Commons IO,仅为了文件复制而引入这个库可能有些多余。此方法适用于希望通过简单方式实现文件复制且项目已使用 Apache Commons IO 的场景。

四.使用 Files 类实现文件复制

如果你使用的是 Java 7 或更高版本,可以使用 java.nio.file.Files 类的 copy() 方法来复制文件。该方法通过文件系统提供器(File System Providers)执行文件复制操作,非常方便和简洁。

以下是使用 Files 类的 copy() 方法 进行文件复制的代码示例

// 使用 Java 7 的 Files.copy 方法实现文件复制

private static void copyFileUsingJava7Files(File source, File dest) throws IOException {

// 使用 Files.copy 方法从源文件的路径 (source.toPath()) 复制数据

// 到目标文件的路径 (dest.toPath())

Files.copy(source.toPath(), dest.toPath());

}

4.1.方法说明

source.toPath():

将源文件 File 对象转换为路径对象(Path)。这是 Files.copy() 方法的输入参数之一。

dest.toPath():

将目标文件 File 对象转换为路径对象(Path)。用于指定复制操作的目标位置。

异常处理:

方法声明抛出 IOException,表明在复制过程中可能会发生 I/O 异常,例如文件不存在或文件不可读写。优点

简洁性:Files.copy() 是一个一行代码的实现,适合需要快速实现文件复制的场景。兼容性:适用于 Java 7 及以上版本。灵活性:支持文件系统的抽象,可以与多种文件系统提供器(例如本地文件系统、虚拟文件系统)一起使用。如果需要进一步扩展,还可以结合 StandardCopyOption 选项,实现例如覆盖目标文件的功能:

// 使用 Files.copy 方法并指定覆盖选项

Files.copy(source.toPath(), dest.toPath(), StandardCopyOption.REPLACE_EXISTING);

这个选项会在目标文件已经存在的情况下覆盖目标文件,避免抛出文件已存在的异常。

五.四种方法对比

为了找出哪种方法最快,我编写了一个测试类,并依次对上述方法进行了测试,用它们来复制一个 1 GB 的文件。每次调用时,我都使用了不同的文件,以避免由于缓存导致后续方法受益。

注意:以下代码中的文件的路径可以改为你自己的文件的路径

// 导入必要的类和包

import java.io.File; // 用于表示文件和目录路径名的抽象表示

import java.io.FileInputStream; // 用于从文件中读取数据的输入流

import java.io.FileOutputStream; // 用于向文件中写入数据的输出流

import java.io.IOException; // 用于处理输入/输出操作中的异常

import java.io.InputStream; // 输入流的通用父类

import java.io.OutputStream; // 输出流的通用父类

import java.nio.channels.FileChannel; // 用于文件通道的复制操作

import java.nio.file.Files; // Java 7 中引入的文件操作类

// 导入 Apache Commons IO 库中的工具类

import org.apache.commons.io.FileUtils; // 提供简单实用的文件操作方法

// 定义主类

public class JavaCopyFile {

// 主方法,程序从这里开始执行

public static void main(String[] args) throws InterruptedException, IOException {

// 定义源文件对象,表示要复制的文件

File source = new File("/Users/pankaj/tmp/source.avi");

// 定义目标文件对象,表示复制的目标位置

File dest = new File("/Users/pankaj/tmp/dest.avi");

// 使用流 (Stream) 方法复制文件

long start = System.nanoTime(); // 记录开始时间

copyFileUsingStream(source, dest); // 调用流方法复制文件

System.out.println("Time taken by Stream Copy = " + (System.nanoTime() - start)); // 打印流方法的执行时间

// 使用 FileChannel 方法复制文件

source = new File("/Users/pankaj/tmp/sourceChannel.avi"); // 定义新的源文件对象

dest = new File("/Users/pankaj/tmp/destChannel.avi"); // 定义新的目标文件对象

start = System.nanoTime(); // 记录开始时间

copyFileUsingChannel(source, dest); // 调用 FileChannel 方法复制文件

System.out.println("Time taken by Channel Copy = " + (System.nanoTime() - start)); // 打印 FileChannel 方法的执行时间

// 使用 Apache Commons IO 工具方法复制文件

source = new File("/Users/pankaj/tmp/sourceApache.avi"); // 定义新的源文件对象

dest = new File("/Users/pankaj/tmp/destApache.avi"); // 定义新的目标文件对象

start = System.nanoTime(); // 记录开始时间

copyFileUsingApacheCommonsIO(source, dest); // 调用 Apache Commons IO 方法复制文件

System.out.println("Time taken by Apache Commons IO Copy = " + (System.nanoTime() - start)); // 打印 Apache Commons IO 方法的执行时间

// 使用 Java 7 的 Files 类复制文件

source = new File("/Users/pankaj/tmp/sourceJava7.avi"); // 定义新的源文件对象

dest = new File("/Users/pankaj/tmp/destJava7.avi"); // 定义新的目标文件对象

start = System.nanoTime(); // 记录开始时间

copyFileUsingJava7Files(source, dest); // 调用 Files 类方法复制文件

System.out.println("Time taken by Java7 Files Copy = " + (System.nanoTime() - start)); // 打印 Files 类方法的执行时间

}

}

以下是上述程序的输出结果,每次只使用一种方法进行 Java 文件复制操作,需要把其他方法相关的代码给注释掉。

Time taken by Stream Copy = 44582575000

Time taken by Channel Copy = 104138195000

Time taken by Apache Commons IO Copy = 108396714000

Time taken by Java7 Files Copy = 89061578000

从输出结果可以看出,流复制(Stream Copy)是 Java 中复制文件的最佳方法。但这只是一个非常基础的测试。如果你正在开发一个对性能要求较高的项目,那么你应该尝试不同的文件复制方法,并记录它们的执行时间,以找到适合你项目的最佳方法。此外,你还可以根据文件的平均大小,尝试不同的 Java 文件复制方式来进行优化。

通过这篇文章,相信你已经掌握了 Java 文件复制的 4 种不同实现方式,并且了解了每种方法的适用场景和性能表现。无论是用于期末作业、毕业设计,还是实际项目开发,选择最优的复制方式,都能让你的代码更高效、更专业!💡

如果这篇文章对你有所帮助,不要忘记 点赞 👍、收藏 ⭐、关注 👀,你的支持是我们分享更多优质内容的动力!🔥 同时,欢迎浏览我们的其他文章,探索更多 Java 技术干货和项目优化技巧。💻 学习之路,你我同行,下一篇更精彩!🚀

相关星际资讯

2025女足世界杯中国队战胜强敌,荣耀与梦想并存!
365bet开户平台

2025女足世界杯中国队战胜强敌,荣耀与梦想并存!

🕒 08-18 👁️ 2333
如何在手机QQ中发送窗口抖动
365体育投注官网

如何在手机QQ中发送窗口抖动

🕒 08-19 👁️ 2213
世界杯小组赛巴西2:1小胜朝鲜
365体育投注官网

世界杯小组赛巴西2:1小胜朝鲜

🕒 07-13 👁️ 5814