remove FileCopier

This commit is contained in:
Looly 2023-03-05 21:04:04 +08:00
parent fb49d79f8b
commit 81b0e95500
10 changed files with 296 additions and 532 deletions

View File

@ -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>
* 1src和dest都为目录则将src下所有文件包括子目录拷贝到dest下
* 2src和dest都为文件直接复制名字为dest
* 3src为文件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();
}
/**

View File

@ -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
}

View 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);
}
}
}

View File

@ -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");
}

View 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 源文件或目录路径

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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() {

View 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"));
}
}

View File

@ -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,