文件复制可以使用封装好的 files.copy(),也可以使用原生的
需求 3: 分别使用文件流和缓冲流复制一个长度大于 100MB 的视频文件,并观察效率的差异。
- 问题: 不知道在文件复制时先使用哪一个
- 关键: 输入流就是在读取数据,输出流就是在写数据
理解清楚两个概念:
- 输入流是 Java 中用于从不同数据源读取数据的流
- 输出流是 Java 中用于将数据写入不同目的地的流
使用文件流复制
为什么需要这两段代码?
第一段代码设置了文件读取和写入的“通道”。
第二段代码实现了文件内容的实际复制。
String sourceFile = "H:\\My_Life_Archive\\Entertainment-娱乐\\VID_20210916_082147.mp4";
String destFile = "H:\\My_Life_Archive\\Entertainment-娱乐\\outputVideo.mp4";
// 使用文件流复制文件
long startTime = System.currentTimeMillis();
// 第一段:创建输入输出流对象
try (FileInputStream readVideo = new FileInputStream(sourceFile);
FileOutputStream writeVideo = new FileOutputStream(destFile)) {
//第二段:读取和写入数据
int byteData;
while ((byteData = readVideo.read()) != -1) {
writeVideo.write(byteData);
}
} catch (IOException e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("文件流复制耗时:" + (endTime - startTime) + "ms");
使用缓冲流复制
创建通道
设置缓冲数组大小
判断是否文件末尾
写入数据
关闭流
String sourceFile = "H:\\My_Life_Archive\\Entertainment-娱乐\\VID_20210916_082147.mp4";
String destFile = "H:\\My_Life_Archive\\Entertainment-娱乐\\outputVideo.mp4";
long startTime = System.currentTimeMillis();
//1.创建通道
try {
BufferedInputStream bufferedReadVideo = new BufferedInputStream(new FileInputStream(sourceFile));
BufferedOutputStream bufferedWriteVideo = new BufferedOutputStream(new FileOutputStream(destFile));
//2.复制内容
byte[] buffer = new byte[1024*1024];
int bytesRead;
while ((bytesRead = bufferedReadVideo.read(buffer)) != -1) {
bufferedWriteVideo.write(buffer, 0, bytesRead);
}
bufferedWriteVideo.flush();
} catch (IOException e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("文件流复制耗时:" + (endTime - startTime) + "ms");
需求 4: 复制文件夹 d:/java 下面所有文件和子文件夹内容到 d:/java2。
前置知识
- listFiles() 方法被调用以获取目录下的所有文件和子目录。
- 使用 java.nio.file.Files.copy() 方法来复制一个文件。这里使用了两个 toPath() 方法将 java.io.File 对象转换成 java.nio.file.Path 对象,以便于使用 Files.copy() 方法进行文件复制
代码实现
/**
* 复制一个目录及其内容到另一个位置。
*
* @param src 源目录
* @param dest 目标目录
*/
private static void copyFolder(File src, File dest) {
// checks
if(src==null || dest==null)
return;
if(!src.isDirectory())
return;
if(dest.exists()){
if(!dest.isDirectory()){
//System.out.println("destination not a folder " + dest);
return;
}
} else {
dest.mkdir();
}
File[] files = src.listFiles();
if(files==null || files.length==0)
return;
for(File file: files){
File fileDest = new File(dest, file.getName());
//System.out.println(fileDest.getAbsolutePath());
if(file.isDirectory()){
copyFolder(file, fileDest);
}else{
if(fileDest.exists())
continue;
try {
Files.copy(file.toPath(), fileDest.toPath());
} catch (IOException e) {
//e.printStackTrace();
}
}
}
}
我总结的关键步骤(符合我编写的步骤)
第一步: 把复制文件的逻辑编写好
- 获取文件列表
- 循环列表
- 初始化目标文件对象
- 判断是否为目录,是就回调本身,不是就复制
第二步: 考虑结束递归的条件
- 确保传入的 src 和 dest 参数都是有效的(非 null)。
- 确保 src 是一个目录。
- 确保 dest 要么是一个已存在的目录,要么是一个可以成功创建的新目录。
AI 总结的整体步骤
参数检查:
if (src == null || dest == null):确保源目录和目标目录都不为 null。
if (!src.isDirectory()):确保源目录确实是一个目录。
if (dest.exists()):检查目标目录是否已经存在。
如果存在且不是一个目录,则直接返回。
如果不存在,则尝试创建目录
获取目录内容:
File[] files = src.listFiles();:获取源目录下的所有文件和子目录。
遍历目录内容:
for (File file : files):遍历目录下的所有文件和子目录。
如果遇到子目录,则递归调用 copyFolder 方法继续复制。
如果遇到普通文件,则检查目标文件是否已存在。
如果已存在,则跳过复制。
如果不存在,则使用 Files.copy 方法复制文件,并使用 REPLACE_EXISTING 选项确保如果目标文件存在则被替换。
评论 (0)