1. 文件及文件夹操作简介
java自身对文件的操作来自于java.io.File类,能够支持:
boolean exists():
Tests whether the file or directory denoted by this abstract pathname exists.
boolean delete():
Deletes the file or directory denoted by this abstract pathname.
boolean mkdir():
Creates the directory named by this abstract pathname.
boolean mkdirs():
Creates the directory named by this abstract pathname, including any necessary but nonexistent parent directories.
boolean renameTo(File dest):
Renames the file denoted by this abstract pathname.
可见,能够进行的操作很有限,不能直接进行复制和移动。对此我们可以有两种方法,一种是通过在java.io.File上建立java.io.FileInputStream和java.io.FileOutputStream,利用字节流进行文件的读取和写入,然而效率不高;另一种是在已经建立的字节流上获取java.nio.channels.FileChannel,利用文件通道来高效实现文件的读取和写入,这种方式是我们要采用的。
注:我们在实现复制和移动操作时,如果将要保存的文件或文件夹已经存在,那么要自动编号命名防止覆盖原始文件(类似于操作系统自身的操作行为)。
2. 代码实现
2.1. 复制
/**
* 复制文件
* 从源路径到目标文件夹路径,文件名保持一致
* 如果目标文件夹不存在则自动创建
* 如果文件已经存在则自动编号-copy n
*
* @param srcFile 源文件绝对路径
* @param dstDir 目标文件夹绝对路径
* @return 是否成功复制文件
*/
public static boolean copyFile(File srcFile, File dstDir) {
if (!srcFile.exists() || srcFile.isDirectory()) {
return false;
}
if (!dstDir.exists()) {
dstDir.mkdirs();
}
String oldFileName = srcFile.getName();
Pattern suffixPattern = Pattern.compile("\\.\\w+");
Matcher matcher = suffixPattern.matcher(oldFileName);
String nameBody;
String suffix;
if (matcher.find()) {
nameBody = oldFileName.substring(0, matcher.start());
suffix = oldFileName.substring(matcher.start());
} else {
nameBody = oldFileName;
suffix = "";
}
int fileNumber = 0;
File newFile = new File(dstDir, oldFileName);
while (newFile.exists()) {
fileNumber++;
String newFileName = nameBody + "-copy" + fileNumber + suffix;
newFile = new File(dstDir, newFileName);
}
try {
FileChannel fileIn = new FileInputStream(srcFile).getChannel();
FileChannel fileOut = new FileOutputStream(newFile).getChannel();
fileIn.transferTo(0, fileIn.size(), fileOut);
fileIn.close();
fileOut.close();
} catch (IOException e) {
return false;
}
return true;
}
/**
* 复制文件或文件夹
* 如果目标文件夹不存在则自动创建
* 如果文件或文件夹已经存在则自动编号-copy n
*
* @param src 源文件或文件夹绝对路径
* @param dstDir 目标文件夹绝对路径
* @return 是否成功复制文件或文件夹
*/
public static boolean copy(File src, File dstDir) {
if (!src.exists()) {
return false;
}
if (!dstDir.exists()) {
dstDir.mkdirs();
}
if (src.isFile()) {// 文件
copyFile(src, dstDir);
} else {// 文件夹
String oldSrcName = src.getName();
int srcNumber = 0;
File newSrcDir = new File(dstDir, oldSrcName);
while (newSrcDir.exists()) {
srcNumber++;
String newSrcName = oldSrcName + "-copy" + srcNumber;
newSrcDir = new File(dstDir, newSrcName);
}
newSrcDir.mkdirs();
for (File srcSub : src.listFiles()) {
copy(srcSub, newSrcDir);// 递归复制源文件夹下子文件和文件夹
}
}
return true;
}
2.2. 移动
/**
* 移动(剪切)文件
*
* @param srcFile
* @param dstDir
* @return
*/
public static boolean moveFile(File srcFile, File dstDir) {
if (!srcFile.exists() || srcFile.isDirectory()) {
return false;
}
if (!dstDir.exists()) {
dstDir.mkdirs();
}
String oldFileName = srcFile.getName();
File dstFile = new File(dstDir, oldFileName);
if (srcFile.renameTo(dstFile)) {// 直接重命名绝对路径速度更快
return true;
} else {// 文件已经存在,需要自动编号复制再删除源文件
copyFile(srcFile, dstDir);
srcFile.delete();
}
return true;
}
/**
* 移动文件或文件夹
* 如果目标文件夹不存在则自动创建
* 如果文件或文件夹已经存在则自动编号-copy n
*
* @param src 源文件或文件夹绝对路径
* @param dstDir 目标文件夹绝对路径
* @return 是否成功移动文件或文件夹
*/
public static boolean move(File src, File dstDir) {
if (!src.exists()) {
return false;
}
if (!dstDir.exists()) {
dstDir.mkdirs();
}
if (src.isFile()) {// 文件
moveFile(src, dstDir);
} else {// 文件夹
String oldSrcName = src.getName();
int srcNumber = 0;
File newSrcDir = new File(dstDir, oldSrcName);
while (newSrcDir.exists()) {
srcNumber++;
String newSrcName = oldSrcName + "-copy" + srcNumber;
newSrcDir = new File(dstDir, newSrcName);
}
newSrcDir.mkdirs();
for (File srcSub : src.listFiles()) {
move(srcSub, newSrcDir);// 递归移动源文件夹下子文件和文件夹
}
src.delete();
}
return true;
}
2.3. 删除
/**
* 删除文件或文件夹
*
* @param src 源文件或文件夹绝对路径
* @return 是否成功删除文件或文件夹
*/
public static boolean delete(File src) {
if (!src.exists()) {
return false;
}
if (src.isFile()) {
src.delete();
} else {
for (File srcSub : src.listFiles()) {
delete(srcSub);// 递归删除源文件夹下子文件和文件夹
}
src.delete();
}
return true;
}
2.4. 测试类
public class FileOperator {
public static void main(String[] args) {
File srcFile1 = new File("E:\\a");
File dstDir1 = new File("E:\\b");
for (int i = 0; i < 5; i++) {
copy(srcFile1, dstDir1);
}
File srcFile2 = new File("E:\\b\\a");
File srcFile3 = new File("E:\\b\\a-copy1");
File srcFile4 = new File("E:\\b\\a-copy2");
File dstDir2 = new File("E:\\c");
move(srcFile2, dstDir2);
move(srcFile3, dstDir2);
move(srcFile4, dstDir2);
delete(srcFile2);
}
}