mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-04-19 03:01:48 +08:00
remove FileCopier
This commit is contained in:
parent
fb49d79f8b
commit
81b0e95500
@ -44,11 +44,7 @@ import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.DirectoryNotEmptyException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.nio.file.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
@ -984,43 +980,6 @@ public class FileUtil extends PathUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过JDK7+的 Files#copy(Path, Path, CopyOption...) 方法拷贝文件
|
||||
*
|
||||
* @param src 源文件路径
|
||||
* @param dest 目标文件或目录路径,如果为目录使用与源文件相同的文件名
|
||||
* @param options {@link StandardCopyOption}
|
||||
* @return File
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
public static File copyFile(final String src, final String dest, final StandardCopyOption... options) throws IORuntimeException {
|
||||
Assert.notBlank(src, "Source File path is blank !");
|
||||
Assert.notBlank(dest, "Destination File path is blank !");
|
||||
return copyFile(Paths.get(src), Paths.get(dest), options).toFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过JDK7+的 Files#copy(Path, Path, CopyOption...) 方法拷贝文件
|
||||
*
|
||||
* @param src 源文件
|
||||
* @param dest 目标文件或目录,如果为目录使用与源文件相同的文件名
|
||||
* @param options {@link StandardCopyOption}
|
||||
* @return 目标文件
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
public static File copyFile(final File src, final File dest, final StandardCopyOption... options) throws IORuntimeException {
|
||||
// check
|
||||
Assert.notNull(src, "Source File is null !");
|
||||
if (false == src.exists()) {
|
||||
throw new IORuntimeException("File not exist: " + src);
|
||||
}
|
||||
Assert.notNull(dest, "Destination File or directiory is null !");
|
||||
if (equals(src, dest)) {
|
||||
throw new IORuntimeException("Files '{}' and '{}' are equal", src, dest);
|
||||
}
|
||||
return copyFile(src.toPath(), dest.toPath(), options).toFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制文件或目录<br>
|
||||
* 如果目标文件为目录,则将源文件以相同文件名拷贝到目标目录
|
||||
@ -1046,13 +1005,19 @@ public class FileUtil extends PathUtil {
|
||||
* </pre>
|
||||
*
|
||||
* @param src 源文件
|
||||
* @param dest 目标文件或目录,目标不存在会自动创建(目录、文件都创建)
|
||||
* @param target 目标文件或目录,目标不存在会自动创建(目录、文件都创建)
|
||||
* @param isOverride 是否覆盖目标文件
|
||||
* @return 目标目录或文件
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
public static File copy(final File src, final File dest, final boolean isOverride) throws IORuntimeException {
|
||||
return FileCopier.of(src, dest).setOverride(isOverride).copy();
|
||||
public static File copy(final File src, final File target, final boolean isOverride) throws IORuntimeException {
|
||||
Assert.notNull(src, "Src file must be not null!");
|
||||
Assert.notNull(target, "target file must be not null!");
|
||||
return PathUtil.copy(
|
||||
src.toPath(),
|
||||
target.toPath(),
|
||||
isOverride ? new CopyOption[]{StandardCopyOption.REPLACE_EXISTING} : new CopyOption[]{})
|
||||
.toFile();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1066,34 +1031,19 @@ public class FileUtil extends PathUtil {
|
||||
* </pre>
|
||||
*
|
||||
* @param src 源文件
|
||||
* @param dest 目标文件或目录,目标不存在会自动创建(目录、文件都创建)
|
||||
* @param target 目标文件或目录,目标不存在会自动创建(目录、文件都创建)
|
||||
* @param isOverride 是否覆盖目标文件
|
||||
* @return 目标目录或文件
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
public static File copyContent(final File src, final File dest, final boolean isOverride) throws IORuntimeException {
|
||||
return FileCopier.of(src, dest).setCopyContentIfDir(true).setOverride(isOverride).copy();
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制文件或目录<br>
|
||||
* 情况如下:
|
||||
*
|
||||
* <pre>
|
||||
* 1、src和dest都为目录,则将src下所有文件(包括子目录)拷贝到dest下
|
||||
* 2、src和dest都为文件,直接复制,名字为dest
|
||||
* 3、src为文件,dest为目录,将src拷贝到dest目录下
|
||||
* </pre>
|
||||
*
|
||||
* @param src 源文件
|
||||
* @param dest 目标文件或目录,目标不存在会自动创建(目录、文件都创建)
|
||||
* @param isOverride 是否覆盖目标文件
|
||||
* @return 目标目录或文件
|
||||
* @throws IORuntimeException IO异常
|
||||
* @since 4.1.5
|
||||
*/
|
||||
public static File copyFilesFromDir(final File src, final File dest, final boolean isOverride) throws IORuntimeException {
|
||||
return FileCopier.of(src, dest).setCopyContentIfDir(true).setOnlyCopyFile(true).setOverride(isOverride).copy();
|
||||
public static File copyContent(final File src, final File target, final boolean isOverride) throws IORuntimeException {
|
||||
Assert.notNull(src, "Src file must be not null!");
|
||||
Assert.notNull(target, "target file must be not null!");
|
||||
return PathUtil.copyContent(
|
||||
src.toPath(),
|
||||
target.toPath(),
|
||||
isOverride ? new CopyOption[]{StandardCopyOption.REPLACE_EXISTING} : new CopyOption[]{})
|
||||
.toFile();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,313 +0,0 @@
|
||||
package cn.hutool.core.io.file;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.lang.copier.SrcToDestCopier;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.text.StrUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.CopyOption;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* 文件拷贝器<br>
|
||||
* 支持以下几种情况:
|
||||
* <pre>
|
||||
* 1、文件复制到文件
|
||||
* 2、文件复制到目录
|
||||
* 3、目录复制到目录
|
||||
* 4、目录下的文件和目录复制到另一个目录
|
||||
* </pre>
|
||||
*
|
||||
* @author Looly
|
||||
* @since 3.0.9
|
||||
*/
|
||||
public class FileCopier extends SrcToDestCopier<File, FileCopier> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 是否覆盖目标文件
|
||||
*/
|
||||
private boolean isOverride;
|
||||
/**
|
||||
* 是否拷贝所有属性
|
||||
*/
|
||||
private boolean isCopyAttributes;
|
||||
/**
|
||||
* 当拷贝来源是目录时是否只拷贝目录下的内容
|
||||
*/
|
||||
private boolean isCopyContentIfDir;
|
||||
/**
|
||||
* 当拷贝来源是目录时是否只拷贝文件而忽略子目录
|
||||
*/
|
||||
private boolean isOnlyCopyFile;
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------- static method start
|
||||
|
||||
/**
|
||||
* 新建一个文件复制器
|
||||
*
|
||||
* @param srcPath 源文件路径(相对ClassPath路径或绝对路径)
|
||||
* @param destPath 目标文件路径(相对ClassPath路径或绝对路径)
|
||||
* @return this
|
||||
*/
|
||||
public static FileCopier of(final String srcPath, final String destPath) {
|
||||
return new FileCopier(FileUtil.file(srcPath), FileUtil.file(destPath));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新建一个文件复制器
|
||||
*
|
||||
* @param src 源文件
|
||||
* @param dest 目标文件
|
||||
* @return this
|
||||
*/
|
||||
public static FileCopier of(final File src, final File dest) {
|
||||
return new FileCopier(src, dest);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------- static method end
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------- Constructor start
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param src 源文件
|
||||
* @param dest 目标文件
|
||||
*/
|
||||
public FileCopier(final File src, final File dest) {
|
||||
this.src = src;
|
||||
this.dest = dest;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------- Constructor end
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------- Getters and Setters start
|
||||
|
||||
/**
|
||||
* 是否覆盖目标文件
|
||||
*
|
||||
* @return 是否覆盖目标文件
|
||||
*/
|
||||
public boolean isOverride() {
|
||||
return isOverride;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置是否覆盖目标文件
|
||||
*
|
||||
* @param isOverride 是否覆盖目标文件
|
||||
* @return this
|
||||
*/
|
||||
public FileCopier setOverride(final boolean isOverride) {
|
||||
this.isOverride = isOverride;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否拷贝所有属性
|
||||
*
|
||||
* @return 是否拷贝所有属性
|
||||
*/
|
||||
public boolean isCopyAttributes() {
|
||||
return isCopyAttributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置是否拷贝所有属性
|
||||
*
|
||||
* @param isCopyAttributes 是否拷贝所有属性
|
||||
* @return this
|
||||
*/
|
||||
public FileCopier setCopyAttributes(final boolean isCopyAttributes) {
|
||||
this.isCopyAttributes = isCopyAttributes;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当拷贝来源是目录时是否只拷贝目录下的内容
|
||||
*
|
||||
* @return 当拷贝来源是目录时是否只拷贝目录下的内容
|
||||
*/
|
||||
public boolean isCopyContentIfDir() {
|
||||
return isCopyContentIfDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当拷贝来源是目录时是否只拷贝目录下的内容
|
||||
*
|
||||
* @param isCopyContentIfDir 是否只拷贝目录下的内容
|
||||
* @return this
|
||||
*/
|
||||
public FileCopier setCopyContentIfDir(final boolean isCopyContentIfDir) {
|
||||
this.isCopyContentIfDir = isCopyContentIfDir;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当拷贝来源是目录时是否只拷贝文件而忽略子目录
|
||||
*
|
||||
* @return 当拷贝来源是目录时是否只拷贝文件而忽略子目录
|
||||
* @since 4.1.5
|
||||
*/
|
||||
public boolean isOnlyCopyFile() {
|
||||
return isOnlyCopyFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当拷贝来源是目录时是否只拷贝文件而忽略子目录
|
||||
*
|
||||
* @param isOnlyCopyFile 当拷贝来源是目录时是否只拷贝文件而忽略子目录
|
||||
* @return this
|
||||
* @since 4.1.5
|
||||
*/
|
||||
public FileCopier setOnlyCopyFile(final boolean isOnlyCopyFile) {
|
||||
this.isOnlyCopyFile = isOnlyCopyFile;
|
||||
return this;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------- Getters and Setters end
|
||||
|
||||
/**
|
||||
* 执行拷贝<br>
|
||||
* 拷贝规则为:
|
||||
* <pre>
|
||||
* 1、源为文件,目标为已存在目录,则拷贝到目录下,文件名不变
|
||||
* 2、源为文件,目标为不存在路径,则目标以文件对待(自动创建父级目录)比如:/dest/aaa,如果aaa不存在,则aaa被当作文件名
|
||||
* 3、源为文件,目标是一个已存在的文件,则当{@link #setOverride(boolean)}设为true时会被覆盖,默认不覆盖
|
||||
* 4、源为目录,目标为已存在目录,当{@link #setCopyContentIfDir(boolean)}为true时,只拷贝目录中的内容到目标目录中,否则整个源目录连同其目录拷贝到目标目录中
|
||||
* 5、源为目录,目标为不存在路径,则自动创建目标为新目录,然后按照规则4复制
|
||||
* 6、源为目录,目标为文件,抛出IO异常
|
||||
* 7、源路径和目标路径相同时,抛出IO异常
|
||||
* </pre>
|
||||
*
|
||||
* @return 拷贝后目标的文件或目录
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
@Override
|
||||
public File copy() throws IORuntimeException {
|
||||
final File src = this.src;
|
||||
File dest = this.dest;
|
||||
// check
|
||||
Assert.notNull(src, "Source File is null !");
|
||||
if (false == src.exists()) {
|
||||
throw new IORuntimeException("File not exist: " + src);
|
||||
}
|
||||
Assert.notNull(dest, "Destination File or directiory is null !");
|
||||
if (FileUtil.equals(src, dest)) {
|
||||
throw new IORuntimeException("Files '{}' and '{}' are equal", src, dest);
|
||||
}
|
||||
|
||||
if (src.isDirectory()) {// 复制目录
|
||||
if (dest.exists() && false == dest.isDirectory()) {
|
||||
//源为目录,目标为文件,抛出IO异常
|
||||
throw new IORuntimeException("Src is a directory but dest is a file!");
|
||||
}
|
||||
if (FileUtil.isSub(src, dest)) {
|
||||
throw new IORuntimeException("Dest is a sub directory of src !");
|
||||
}
|
||||
|
||||
final File subTarget = isCopyContentIfDir ? dest : FileUtil.mkdir(FileUtil.file(dest, src.getName()));
|
||||
internalCopyDirContent(src, subTarget);
|
||||
} else {// 复制文件
|
||||
dest = internalCopyFile(src, dest);
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------- Private method start
|
||||
|
||||
/**
|
||||
* 拷贝目录内容,只用于内部,不做任何安全检查<br>
|
||||
* 拷贝内容的意思为源目录下的所有文件和目录拷贝到另一个目录下,而不拷贝源目录本身
|
||||
*
|
||||
* @param src 源目录
|
||||
* @param dest 目标目录
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
private void internalCopyDirContent(final File src, final File dest) throws IORuntimeException {
|
||||
if (null != copyPredicate && false == copyPredicate.test(src)) {
|
||||
//被过滤的目录跳过
|
||||
return;
|
||||
}
|
||||
|
||||
if (false == dest.exists()) {
|
||||
//目标为不存在路径,创建为目录
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
dest.mkdirs();
|
||||
} else if (false == dest.isDirectory()) {
|
||||
throw new IORuntimeException(StrUtil.format("Src [{}] is a directory but dest [{}] is a file!", src.getPath(), dest.getPath()));
|
||||
}
|
||||
|
||||
final String[] files = src.list();
|
||||
if (ArrayUtil.isNotEmpty(files)) {
|
||||
File srcFile;
|
||||
File destFile;
|
||||
for (final String file : files) {
|
||||
srcFile = new File(src, file);
|
||||
destFile = this.isOnlyCopyFile ? dest : new File(dest, file);
|
||||
// 递归复制
|
||||
if (srcFile.isDirectory()) {
|
||||
internalCopyDirContent(srcFile, destFile);
|
||||
} else {
|
||||
internalCopyFile(srcFile, destFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 拷贝文件,只用于内部,不做任何安全检查<br>
|
||||
* 情况如下:
|
||||
* <pre>
|
||||
* 1、如果目标是一个不存在的路径,则目标以文件对待(自动创建父级目录)比如:/dest/aaa,如果aaa不存在,则aaa被当作文件名
|
||||
* 2、如果目标是一个已存在的目录,则文件拷贝到此目录下,文件名与原文件名一致
|
||||
* </pre>
|
||||
*
|
||||
* @param src 源文件,必须为文件
|
||||
* @param dest 目标文件,如果非覆盖模式必须为目录
|
||||
* @return 目标文件
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
private File internalCopyFile(final File src, File dest) throws IORuntimeException {
|
||||
if (null != copyPredicate && false == copyPredicate.test(src)) {
|
||||
//被过滤的文件跳过
|
||||
return dest;
|
||||
}
|
||||
|
||||
// 如果已经存在目标文件,切为不覆盖模式,跳过之
|
||||
if (dest.exists()) {
|
||||
if (dest.isDirectory()) {
|
||||
//目标为目录,目录下创建同名文件
|
||||
dest = new File(dest, src.getName());
|
||||
}
|
||||
|
||||
if (dest.exists() && false == isOverride) {
|
||||
//非覆盖模式跳过
|
||||
return dest;
|
||||
}
|
||||
} else {
|
||||
//路径不存在则创建父目录
|
||||
FileUtil.mkParentDirs(dest);
|
||||
}
|
||||
|
||||
final ArrayList<CopyOption> optionList = new ArrayList<>(2);
|
||||
if (isOverride) {
|
||||
optionList.add(StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
if (isCopyAttributes) {
|
||||
optionList.add(StandardCopyOption.COPY_ATTRIBUTES);
|
||||
}
|
||||
|
||||
try {
|
||||
Files.copy(src.toPath(), dest.toPath(), optionList.toArray(new CopyOption[0]));
|
||||
} catch (final IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------- Private method end
|
||||
}
|
165
hutool-core/src/main/java/cn/hutool/core/io/file/PathCopier.java
Executable file
165
hutool-core/src/main/java/cn/hutool/core/io/file/PathCopier.java
Executable file
@ -0,0 +1,165 @@
|
||||
package cn.hutool.core.io.file;
|
||||
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.io.file.visitor.CopyVisitor;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.lang.copier.SrcToDestCopier;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.*;
|
||||
|
||||
/**
|
||||
* 文件复制封装
|
||||
*
|
||||
* @author looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public class PathCopier extends SrcToDestCopier<Path, PathCopier> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 创建文件或目录拷贝器
|
||||
*
|
||||
* @param src 源文件或目录
|
||||
* @param target 目标文件或目录
|
||||
* @param isOverride 是否覆盖目标文件
|
||||
* @return {@code PathCopier}
|
||||
*/
|
||||
public static PathCopier of(final Path src, final Path target, final boolean isOverride) {
|
||||
return of(src, target, isOverride ? new CopyOption[]{StandardCopyOption.REPLACE_EXISTING} : new CopyOption[]{});
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建文件或目录拷贝器
|
||||
*
|
||||
* @param src 源文件或目录
|
||||
* @param target 目标文件或目录
|
||||
* @param options 拷贝参数
|
||||
* @return {@code PathCopier}
|
||||
*/
|
||||
public static PathCopier of(final Path src, final Path target, final CopyOption[] options) {
|
||||
return new PathCopier(src, target, options);
|
||||
}
|
||||
|
||||
private final CopyOption[] options;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param src 源文件或目录,不能为{@code null}且必须存在
|
||||
* @param target 目标文件或目录
|
||||
* @param options 移动参数
|
||||
*/
|
||||
public PathCopier(final Path src, final Path target, final CopyOption[] options) {
|
||||
Assert.notNull(target, "Src path must be not null !");
|
||||
if (false == PathUtil.exists(src, false)) {
|
||||
throw new IllegalArgumentException("Src path is not exist!");
|
||||
}
|
||||
this.src = src;
|
||||
this.target = Assert.notNull(target, "Target path must be not null !");
|
||||
this.options = ObjUtil.defaultIfNull(options, new CopyOption[]{});
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制src到target中
|
||||
* <ul>
|
||||
* <li>src路径和target路径相同时,不执行操作</li>
|
||||
* <li>src为文件,target为已存在目录,则拷贝到目录下,文件名不变。</li>
|
||||
* <li>src为文件,target为不存在路径,则目标以文件对待(自动创建父级目录),相当于拷贝后重命名,比如:/dest/aaa,如果aaa不存在,则aaa被当作文件名</li>
|
||||
* <li>src为文件,target是一个已存在的文件,则当{@link CopyOption}设为覆盖时会被覆盖,默认不覆盖,抛出{@link FileAlreadyExistsException}</li>
|
||||
* <li>src为目录,target为已存在目录,整个src目录连同其目录拷贝到目标目录中</li>
|
||||
* <li>src为目录,target为不存在路径,则自动创建目标为新目录,并只拷贝src内容到目标目录中,相当于重命名目录。</li>
|
||||
* <li>src为目录,target为文件,抛出{@link IllegalArgumentException}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @return 目标Path
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
@Override
|
||||
public Path copy() throws IORuntimeException {
|
||||
if (PathUtil.isDirectory(src)) {
|
||||
if (PathUtil.exists(target, false)) {
|
||||
if (PathUtil.isDirectory(target)) {
|
||||
return _copyContent(src, target.resolve(src.getFileName()), options);
|
||||
} else {
|
||||
// src目录,target文件,无法拷贝
|
||||
throw new IllegalArgumentException("Can not copy directory to a file!");
|
||||
}
|
||||
} else {
|
||||
// 目标不存在,按照重命名对待
|
||||
return _copyContent(src, target, options);
|
||||
}
|
||||
}
|
||||
return copyFile(src, target, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制src的内容到target中
|
||||
* <ul>
|
||||
* <li>src路径和target路径相同时,不执行操作</li>
|
||||
* <li>src为文件,target为已存在目录,则拷贝到目录下,文件名不变。</li>
|
||||
* <li>src为文件,target为不存在路径,则目标以文件对待(自动创建父级目录),相当于拷贝后重命名,比如:/dest/aaa,如果aaa不存在,则aaa被当作文件名</li>
|
||||
* <li>src为文件,target是一个已存在的文件,则当{@link CopyOption}设为覆盖时会被覆盖,默认不覆盖,抛出{@link FileAlreadyExistsException}</li>
|
||||
* <li>src为目录,target为已存在目录,整个src目录下的内容拷贝到目标目录中</li>
|
||||
* <li>src为目录,target为不存在路径,则自动创建目标为新目录,整个src目录下的内容拷贝到目标目录中,相当于重命名目录。</li>
|
||||
* <li>src为目录,target为文件,抛出IO异常</li>
|
||||
* </ul>
|
||||
*
|
||||
* @return 目标Path
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
public Path copyContent() throws IORuntimeException {
|
||||
if (PathUtil.isDirectory(src, false)) {
|
||||
return _copyContent(src, target, options);
|
||||
}
|
||||
return copyFile(src, target, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 拷贝目录下的所有文件或目录到目标目录中,此方法不支持文件对文件的拷贝。
|
||||
* <ul>
|
||||
* <li>源文件为目录,目标也为目录或不存在,则拷贝目录下所有文件和目录到目标目录下</li>
|
||||
* <li>源文件为文件,目标为目录或不存在,则拷贝文件到目标目录下</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param src 源文件路径,如果为目录只在目标中创建新目录
|
||||
* @param target 目标目录,如果为目录使用与源文件相同的文件名
|
||||
* @param options {@link StandardCopyOption}
|
||||
* @return Path
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
private static Path _copyContent(final Path src, final Path target, final CopyOption... options) throws IORuntimeException {
|
||||
try {
|
||||
Files.walkFileTree(src, new CopyVisitor(src, target, options));
|
||||
} catch (final IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过JDK7+的 {@link Files#copy(Path, Path, CopyOption...)} 方法拷贝文件<br>
|
||||
* 此方法不支持递归拷贝目录,如果src传入是目录,只会在目标目录中创建空目录
|
||||
*
|
||||
* @param src 源文件路径,如果为目录只在目标中创建新目录
|
||||
* @param target 目标文件或目录,如果为目录使用与源文件相同的文件名
|
||||
* @param options {@link StandardCopyOption}
|
||||
* @return Path
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
private static Path copyFile(final Path src, final Path target, final CopyOption... options) throws IORuntimeException {
|
||||
Assert.notNull(src, "Source File is null !");
|
||||
Assert.notNull(target, "Destination File or directory is null !");
|
||||
|
||||
final Path targetPath = PathUtil.isDirectory(target) ? target.resolve(src.getFileName()) : target;
|
||||
// 创建级联父目录
|
||||
PathUtil.mkParentDirs(targetPath);
|
||||
try {
|
||||
return Files.copy(src, targetPath, options);
|
||||
} catch (final IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
package cn.hutool.core.io.file;
|
||||
|
||||
import cn.hutool.core.bean.copier.CopyOptions;
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.io.file.visitor.MoveVisitor;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
@ -117,21 +116,21 @@ public class PathMover {
|
||||
* <li>如果src为文件,target为文件,则按照是否覆盖参数执行。</li>
|
||||
* <li>如果src为文件,target为不存在的路径,则重命名源文件到目标指定的文件,如moveContent("/a/b", "/c/d"), d不存在,则b变成d。</li>
|
||||
* <li>如果src为目录,target为文件,抛出{@link IllegalArgumentException}</li>
|
||||
* <li>如果src为目录,target为目录,则将源目录下的内容移动到目标路径目录中。</li>
|
||||
* <li>如果src为目录,target为不存在的路径,则创建目标路径为目录,将源目录下的内容移动到目标路径目录中。</li>
|
||||
* <li>如果src为目录,target为目录,则将源目录下的内容移动到目标路径目录中,源目录不删除。</li>
|
||||
* <li>如果src为目录,target为不存在的路径,则创建目标路径为目录,将源目录下的内容移动到目标路径目录中,源目录不删除。</li>
|
||||
* </ul>
|
||||
*
|
||||
* @return 目标文件Path
|
||||
*/
|
||||
public Path moveContent() {
|
||||
final Path src = this.src;
|
||||
if (PathUtil.isNotDirectory(target, false)) {
|
||||
if (PathUtil.isExistsAndNotDirectory(target, false)) {
|
||||
// 文件移动调用move方法
|
||||
return move();
|
||||
}
|
||||
|
||||
final Path target = this.target;
|
||||
if (PathUtil.isNotDirectory(target, false)) {
|
||||
if (PathUtil.isExistsAndNotDirectory(target, false)) {
|
||||
// 目标不能为文件
|
||||
throw new IllegalArgumentException("Can not move dir content to a file");
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package cn.hutool.core.io.file;
|
||||
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.io.file.visitor.CopyVisitor;
|
||||
import cn.hutool.core.io.file.visitor.DelVisitor;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
@ -150,51 +149,15 @@ public class PathUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过JDK7+的 {@link Files#copy(Path, Path, CopyOption...)} 方法拷贝文件<br>
|
||||
* 此方法不支持递归拷贝目录,如果src传入是目录,只会在目标目录中创建空目录
|
||||
*
|
||||
* @param src 源文件路径,如果为目录只在目标中创建新目录
|
||||
* @param dest 目标文件或目录,如果为目录使用与源文件相同的文件名
|
||||
* @param options {@link StandardCopyOption}
|
||||
* @return Path
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
public static Path copyFile(final Path src, final Path dest, final StandardCopyOption... options) throws IORuntimeException {
|
||||
return copyFile(src, dest, (CopyOption[]) options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过JDK7+的 {@link Files#copy(Path, Path, CopyOption...)} 方法拷贝文件<br>
|
||||
* 此方法不支持递归拷贝目录,如果src传入是目录,只会在目标目录中创建空目录
|
||||
*
|
||||
* @param src 源文件路径,如果为目录只在目标中创建新目录
|
||||
* @param target 目标文件或目录,如果为目录使用与源文件相同的文件名
|
||||
* @param options {@link StandardCopyOption}
|
||||
* @return Path
|
||||
* @throws IORuntimeException IO异常
|
||||
* @since 5.4.1
|
||||
*/
|
||||
public static Path copyFile(final Path src, final Path target, final CopyOption... options) throws IORuntimeException {
|
||||
Assert.notNull(src, "Source File is null !");
|
||||
Assert.notNull(target, "Destination File or directory is null !");
|
||||
|
||||
final Path targetPath = isDirectory(target) ? target.resolve(src.getFileName()) : target;
|
||||
// 创建级联父目录
|
||||
mkParentDirs(targetPath);
|
||||
try {
|
||||
return Files.copy(src, targetPath, options);
|
||||
} catch (final IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 拷贝文件或目录,拷贝规则为:
|
||||
*
|
||||
* 复制src到target中
|
||||
* <ul>
|
||||
* <li>源文件为目录,目标也为目录或不存在,则拷贝整个目录到目标目录下</li>
|
||||
* <li>源文件为文件,目标为目录或不存在,则拷贝文件到目标目录下</li>
|
||||
* <li>源文件为文件,目标也为文件,则在{@link StandardCopyOption#REPLACE_EXISTING}情况下覆盖之</li>
|
||||
* <li>src路径和target路径相同时,不执行操作</li>
|
||||
* <li>src为文件,target为已存在目录,则拷贝到目录下,文件名不变。</li>
|
||||
* <li>src为文件,target为不存在路径,则目标以文件对待(自动创建父级目录),相当于拷贝后重命名,比如:/dest/aaa,如果aaa不存在,则aaa被当作文件名</li>
|
||||
* <li>src为文件,target是一个已存在的文件,则当{@link CopyOption}设为覆盖时会被覆盖,默认不覆盖,抛出{@link FileAlreadyExistsException}</li>
|
||||
* <li>src为目录,target为已存在目录,整个src目录连同其目录拷贝到目标目录中</li>
|
||||
* <li>src为目录,target为不存在路径,则自动创建目标为新目录,并只拷贝src内容到目标目录中,相当于重命名目录。</li>
|
||||
* <li>src为目录,target为文件,抛出{@link IllegalArgumentException}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param src 源文件路径,如果为目录会在目标中创建新目录
|
||||
@ -202,23 +165,21 @@ public class PathUtil {
|
||||
* @param options {@link StandardCopyOption}
|
||||
* @return Path
|
||||
* @throws IORuntimeException IO异常
|
||||
* @since 5.5.1
|
||||
*/
|
||||
public static Path copy(final Path src, final Path target, final CopyOption... options) throws IORuntimeException {
|
||||
Assert.notNull(src, "Src path must be not null !");
|
||||
Assert.notNull(target, "Target path must be not null !");
|
||||
|
||||
if (isDirectory(src)) {
|
||||
return copyContent(src, target.resolve(src.getFileName()), options);
|
||||
}
|
||||
return copyFile(src, target, options);
|
||||
return PathCopier.of(src, target, options).copy();
|
||||
}
|
||||
|
||||
/**
|
||||
* 拷贝目录下的所有文件或目录到目标目录中,此方法不支持文件对文件的拷贝。
|
||||
* 复制src的内容到target中
|
||||
* <ul>
|
||||
* <li>源文件为目录,目标也为目录或不存在,则拷贝目录下所有文件和目录到目标目录下</li>
|
||||
* <li>源文件为文件,目标为目录或不存在,则拷贝文件到目标目录下</li>
|
||||
* <li>src路径和target路径相同时,不执行操作</li>
|
||||
* <li>src为文件,target为已存在目录,则拷贝到目录下,文件名不变。</li>
|
||||
* <li>src为文件,target为不存在路径,则目标以文件对待(自动创建父级目录),相当于拷贝后重命名,比如:/dest/aaa,如果aaa不存在,则aaa被当作文件名</li>
|
||||
* <li>src为文件,target是一个已存在的文件,则当{@link CopyOption}设为覆盖时会被覆盖,默认不覆盖,抛出{@link FileAlreadyExistsException}</li>
|
||||
* <li>src为目录,target为已存在目录,整个src目录下的内容拷贝到目标目录中</li>
|
||||
* <li>src为目录,target为不存在路径,则自动创建目标为新目录,整个src目录下的内容拷贝到目标目录中,相当于重命名目录。</li>
|
||||
* <li>src为目录,target为文件,抛出IO异常</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param src 源文件路径,如果为目录只在目标中创建新目录
|
||||
@ -226,18 +187,9 @@ public class PathUtil {
|
||||
* @param options {@link StandardCopyOption}
|
||||
* @return Path
|
||||
* @throws IORuntimeException IO异常
|
||||
* @since 5.5.1
|
||||
*/
|
||||
public static Path copyContent(final Path src, final Path target, final CopyOption... options) throws IORuntimeException {
|
||||
Assert.notNull(src, "Src path must be not null !");
|
||||
Assert.notNull(target, "Target path must be not null !");
|
||||
|
||||
try {
|
||||
Files.walkFileTree(src, new CopyVisitor(src, target, options));
|
||||
} catch (final IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
return target;
|
||||
return PathCopier.of(src, target, options).copyContent();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -253,7 +205,7 @@ public class PathUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为非目录
|
||||
* 判断是否存在且为非目录
|
||||
* <ul>
|
||||
* <li>如果path为{@code null},返回{@code false}</li>
|
||||
* <li>如果path不存在,返回{@code false}</li>
|
||||
@ -264,7 +216,7 @@ public class PathUtil {
|
||||
* @return 如果为目录true
|
||||
* @since 3.1.0
|
||||
*/
|
||||
public static boolean isNotDirectory(final Path path, final boolean isFollowLinks) {
|
||||
public static boolean isExistsAndNotDirectory(final Path path, final boolean isFollowLinks) {
|
||||
return exists(path, isFollowLinks) && false == isDirectory(path, isFollowLinks);
|
||||
}
|
||||
|
||||
@ -495,8 +447,8 @@ public class PathUtil {
|
||||
* <li>如果src为文件,target为文件,则按照是否覆盖参数执行。</li>
|
||||
* <li>如果src为文件,target为不存在的路径,则重命名源文件到目标指定的文件,如moveContent("/a/b", "/c/d"), d不存在,则b变成d。</li>
|
||||
* <li>如果src为目录,target为文件,抛出{@link IllegalArgumentException}</li>
|
||||
* <li>如果src为目录,target为目录,则将源目录下的内容移动到目标路径目录中。</li>
|
||||
* <li>如果src为目录,target为不存在的路径,则创建目标路径为目录,将源目录下的内容移动到目标路径目录中。</li>
|
||||
* <li>如果src为目录,target为目录,则将源目录下的内容移动到目标路径目录中,源目录不删除。</li>
|
||||
* <li>如果src为目录,target为不存在的路径,则创建目标路径为目录,将源目录下的内容移动到目标路径目录中,源目录不删除。</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param src 源文件或目录路径
|
||||
|
@ -19,7 +19,7 @@ public abstract class SrcToDestCopier<T, C extends SrcToDestCopier<T, C>> implem
|
||||
/** 源 */
|
||||
protected T src;
|
||||
/** 目标 */
|
||||
protected T dest;
|
||||
protected T target;
|
||||
/** 拷贝过滤器,可以过滤掉不需要拷贝的源 */
|
||||
protected Predicate<T> copyPredicate;
|
||||
|
||||
@ -48,18 +48,18 @@ public abstract class SrcToDestCopier<T, C extends SrcToDestCopier<T, C>> implem
|
||||
*
|
||||
* @return 目标
|
||||
*/
|
||||
public T getDest() {
|
||||
return dest;
|
||||
public T getTarget() {
|
||||
return target;
|
||||
}
|
||||
/**
|
||||
* 设置目标
|
||||
*
|
||||
* @param dest 目标
|
||||
* @param target 目标
|
||||
* @return this
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public C setDest(final T dest) {
|
||||
this.dest = dest;
|
||||
public C setTarget(final T target) {
|
||||
this.target = target;
|
||||
return (C)this;
|
||||
}
|
||||
|
||||
|
@ -1,59 +0,0 @@
|
||||
package cn.hutool.core.io;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import cn.hutool.core.io.file.FileCopier;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* 文件拷贝单元测试
|
||||
*
|
||||
* @author Looly
|
||||
*/
|
||||
public class FileCopierTest {
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void dirCopyTest() {
|
||||
final FileCopier copier = FileCopier.of("D:\\Java", "e:/eclipse/eclipse2.zip");
|
||||
copier.copy();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void dirCopyTest2() {
|
||||
//测试带.的文件夹复制
|
||||
final FileCopier copier = FileCopier.of("D:\\workspace\\java\\.metadata", "D:\\workspace\\java\\.metadata\\temp");
|
||||
copier.copy();
|
||||
|
||||
FileUtil.copy("D:\\workspace\\java\\looly\\hutool\\.git", "D:\\workspace\\java\\temp", true);
|
||||
}
|
||||
|
||||
@Test(expected = IORuntimeException.class)
|
||||
public void dirCopySubTest() {
|
||||
//测试父目录复制到子目录报错
|
||||
final FileCopier copier = FileCopier.of("D:\\workspace\\java\\.metadata", "D:\\workspace\\java\\.metadata\\temp");
|
||||
copier.copy();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void copyFileToDirTest() {
|
||||
final FileCopier copier = FileCopier.of("d:/GReen_Soft/XshellXftpPortable.zip", "c:/hp/");
|
||||
copier.copy();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void copyFileByRelativePath(){
|
||||
// https://github.com/dromara/hutool/pull/2188
|
||||
// 当复制的目标文件位置是相对路径的时候可以通过
|
||||
final FileCopier copier = FileCopier.of(new File("pom.xml"),new File("aaa.txt"));
|
||||
copier.copy();
|
||||
final boolean delete = new File("aaa.txt").delete();
|
||||
Assert.assertTrue(delete);
|
||||
}
|
||||
}
|
@ -92,15 +92,6 @@ public class FileUtilTest {
|
||||
Assert.assertEquals(srcFile.length(), destFile.length());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void copyFilesFromDirTest() {
|
||||
final File srcFile = FileUtil.file("D:\\驱动");
|
||||
final File destFile = FileUtil.file("d:\\驱动备份");
|
||||
|
||||
FileUtil.copyFilesFromDir(srcFile, destFile, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void copyDirTest() {
|
||||
|
79
hutool-core/src/test/java/cn/hutool/core/io/file/PathCopyTest.java
Executable file
79
hutool-core/src/test/java/cn/hutool/core/io/file/PathCopyTest.java
Executable file
@ -0,0 +1,79 @@
|
||||
package cn.hutool.core.io.file;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* 文件或目录拷贝测试
|
||||
*/
|
||||
public class PathCopyTest {
|
||||
|
||||
@Test
|
||||
public void copySameFileTest() {
|
||||
final Path path = Paths.get("d:/test/dir1/test1.txt");
|
||||
//src路径和target路径相同时,不执行操作
|
||||
PathUtil.copy(
|
||||
path,
|
||||
path);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copySameDirTest() {
|
||||
final Path path = Paths.get("d:/test/dir1");
|
||||
//src路径和target路径相同时,不执行操作
|
||||
PathUtil.copyContent(
|
||||
path,
|
||||
path);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyFileToDirTest() {
|
||||
// src为文件,target为已存在目录,则拷贝到目录下,文件名不变。
|
||||
PathUtil.copy(
|
||||
Paths.get("d:/test/dir1/test1.txt"),
|
||||
Paths.get("d:/test/dir2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyFileToPathNotExistTest() {
|
||||
// src为文件,target为不存在路径,则目标以文件对待(自动创建父级目录)
|
||||
// 相当于拷贝后重命名
|
||||
PathUtil.copy(
|
||||
Paths.get("d:/test/dir1/test1.txt"),
|
||||
Paths.get("d:/test/test2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyFileToFileTest() {
|
||||
//src为文件,target是一个已存在的文件,则当{@link CopyOption}设为覆盖时会被覆盖,默认不覆盖。
|
||||
PathUtil.copy(
|
||||
Paths.get("d:/test/dir1/test1.txt"),
|
||||
Paths.get("d:/test/test2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyDirToDirTest() {
|
||||
//src为目录,target为已存在目录,整个src目录连同其目录拷贝到目标目录中
|
||||
PathUtil.copy(
|
||||
Paths.get("d:/test/dir1/"),
|
||||
Paths.get("d:/test/dir2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyDirToPathNotExistTest() {
|
||||
//src为目录,target为不存在路径,则自动创建目标为新目录,整个src目录连同其目录拷贝到目标目录中
|
||||
PathUtil.copy(
|
||||
Paths.get("d:/test/dir1/"),
|
||||
Paths.get("d:/test/dir3"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyDirToFileTest() {
|
||||
//src为目录,target为文件,抛出IllegalArgumentException
|
||||
PathUtil.copy(
|
||||
Paths.get("d:/test/dir1/"),
|
||||
Paths.get("d:/test/exist.txt"));
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@ public class PathUtilTest {
|
||||
@Test
|
||||
@Ignore
|
||||
public void copyFileTest(){
|
||||
PathUtil.copyFile(
|
||||
PathUtil.copy(
|
||||
Paths.get("d:/test/1595232240113.jpg"),
|
||||
Paths.get("d:/test/1595232240113_copy.jpg"),
|
||||
StandardCopyOption.COPY_ATTRIBUTES,
|
||||
|
Loading…
x
Reference in New Issue
Block a user