From fb49d79f8b6c7a2b01ff4f1c58a1b9a542d723e1 Mon Sep 17 00:00:00 2001 From: Looly Date: Sun, 5 Mar 2023 19:59:00 +0800 Subject: [PATCH] fixcode --- .../cn/hutool/core/io/file/PathMover.java | 71 ++++++++++++------- .../java/cn/hutool/core/io/file/PathUtil.java | 25 ++++++- .../hutool/core/io/file/IssueI666HBTest.java | 42 ++++++++++- 3 files changed, 109 insertions(+), 29 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/io/file/PathMover.java b/hutool-core/src/main/java/cn/hutool/core/io/file/PathMover.java index 30c53a11c..4427b41dd 100755 --- a/hutool-core/src/main/java/cn/hutool/core/io/file/PathMover.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/file/PathMover.java @@ -23,7 +23,7 @@ public class PathMover { * @param src 源文件或目录 * @param target 目标文件或目录 * @param isOverride 是否覆盖目标文件 - * @return {@link PathMover} + * @return {@code PathMover} */ public static PathMover of(final Path src, final Path target, final boolean isOverride) { return of(src, target, isOverride ? new CopyOption[]{StandardCopyOption.REPLACE_EXISTING} : new CopyOption[]{}); @@ -35,7 +35,7 @@ public class PathMover { * @param src 源文件或目录 * @param target 目标文件或目录 * @param options 移动参数 - * @return {@link PathMover} + * @return {@code PathMover} */ public static PathMover of(final Path src, final Path target, final CopyOption[] options) { return new PathMover(src, target, options); @@ -48,25 +48,30 @@ public class PathMover { /** * 构造 * - * @param src 源文件或目录 + * @param src 源文件或目录,不能为{@code null}且必须存在 * @param target 目标文件或目录 * @param options 移动参数 */ public PathMover(final Path src, final Path target, final CopyOption[] options) { - this.src = Assert.notNull(src, "Src path must be not null !"); + 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 = options; + this.options = ObjUtil.defaultIfNull(options, new CopyOption[]{});; } /** * 移动文件或目录到目标中,例如: * * * @return 目标文件Path @@ -74,9 +79,9 @@ public class PathMover { public Path move() { final Path src = this.src; Path target = this.target; - final CopyOption[] options = ObjUtil.defaultIfNull(this.options, new CopyOption[]{}); + final CopyOption[] options = this.options; - if (false == PathUtil.exists(target, false) || PathUtil.isDirectory(target)) { + if (PathUtil.isDirectory(target)) { // 创建子路径的情况,1是目标是目录,需要移动到目录下,2是目标不能存在,自动创建目录 target = target.resolve(src.getFileName()); } @@ -98,13 +103,9 @@ public class PathMover { throw new IORuntimeException(e); } // 移动失败,可能是跨分区移动导致的,采用递归移动方式 - try { - Files.walkFileTree(src, new MoveVisitor(src, target, options)); - // 移动后空目录没有删除, - PathUtil.del(src); - } catch (final IOException e2) { - throw new IORuntimeException(e2); - } + walkMove(src, target, options); + // 移动后删除空目录 + PathUtil.del(src); return target; } } @@ -124,25 +125,43 @@ public class PathMover { */ public Path moveContent() { final Path src = this.src; + if (PathUtil.isNotDirectory(target, false)) { + // 文件移动调用move方法 + return move(); + } + final Path target = this.target; - final CopyOption[] options = ObjUtil.defaultIfNull(this.options, new CopyOption[]{}); + if (PathUtil.isNotDirectory(target, false)) { + // 目标不能为文件 + throw new IllegalArgumentException("Can not move dir content to a file"); + } + + // issue#2893 target 不存在导致NoSuchFileException + if (PathUtil.equals(src, target)) { + // issue#2845,当用户传入目标路径与源路径一致时,直接返回,否则会导致删除风险。 + return target; + } + + final CopyOption[] options = this.options; // 移动失败,可能是跨分区移动导致的,采用递归移动方式 + walkMove(src, target, options); + return target; + } + + /** + * 递归移动 + * + * @param src 源目录 + * @param target 目标目录 + * @param options 移动参数 + */ + private static void walkMove(final Path src, final Path target, final CopyOption... options) { try { - if (false == PathUtil.isDirectory(src)) { - // 文件移动到目标目录或文件 - return Files.move(src, target, options); - } - - if (false == PathUtil.isDirectory(target)) { - throw new IllegalArgumentException("Can not move dir content to a file"); - } - // 移动源目录下的内容而不删除目录 Files.walkFileTree(src, new MoveVisitor(src, target, options)); } catch (final IOException e) { throw new IORuntimeException(e); } - return target; } } diff --git a/hutool-core/src/main/java/cn/hutool/core/io/file/PathUtil.java b/hutool-core/src/main/java/cn/hutool/core/io/file/PathUtil.java index e7bb8e108..8a476d37d 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/file/PathUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/file/PathUtil.java @@ -252,6 +252,22 @@ public class PathUtil { return isDirectory(path, false); } + /** + * 判断是否为非目录 + * + * + * @param path {@link Path} + * @param isFollowLinks 是否追踪到软链对应的真实地址 + * @return 如果为目录true + * @since 3.1.0 + */ + public static boolean isNotDirectory(final Path path, final boolean isFollowLinks) { + return exists(path, isFollowLinks) && false == isDirectory(path, isFollowLinks); + } + /** * 判断是否为目录,如果file为null,则返回false * @@ -438,6 +454,7 @@ public class PathUtil { * *
 	 * FileUtil.rename(file, "aaa.jpg", false) xx/xx.png =》xx/aaa.jpg
+	 * FileUtil.rename(dir, "dir2", false) xx/xx/ =》xx/dir2/
 	 * 
* * @param path 被修改的文件 @@ -453,12 +470,13 @@ public class PathUtil { /** * 移动文件或目录到目标中,例如: * * * @param src 源文件或目录路径 @@ -539,12 +557,15 @@ public class PathUtil { /** * 判断文件或目录是否存在 * - * @param path 文件 + * @param path 文件,{@code null}返回{@code false} * @param isFollowLinks 是否跟踪软链(快捷方式) * @return 是否存在 * @since 5.5.3 */ public static boolean exists(final Path path, final boolean isFollowLinks) { + if (null == path) { + return false; + } final LinkOption[] options = isFollowLinks ? new LinkOption[0] : new LinkOption[]{LinkOption.NOFOLLOW_LINKS}; return Files.exists(path, options); } diff --git a/hutool-core/src/test/java/cn/hutool/core/io/file/IssueI666HBTest.java b/hutool-core/src/test/java/cn/hutool/core/io/file/IssueI666HBTest.java index 46285b176..6e16ca2f9 100755 --- a/hutool-core/src/test/java/cn/hutool/core/io/file/IssueI666HBTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/io/file/IssueI666HBTest.java @@ -21,6 +21,16 @@ public class IssueI666HBTest { FileUtil.move(FileUtil.file("d:/test/dir1"), FileUtil.file("d:/test/dir2"), false); } + @Test + @Ignore + public void moveContentDirToDirTest() { + // 目录内容移动到目录 + // 移动内容,不移除目录本身 + PathUtil.moveContent( + FileUtil.file("d:/test/dir1").toPath(), + FileUtil.file("d:/test/dir2").toPath(), false); + } + @Test @Ignore public void moveFileToDirTest() { @@ -29,6 +39,16 @@ public class IssueI666HBTest { FileUtil.move(FileUtil.file("d:/test/dir1/test1.txt"), FileUtil.file("d:/test/dir2"), false); } + @Test + @Ignore + public void moveContentFileToDirTest() { + // 文件移动到目录 + // 会将test1.txt移动到dir2下,变成dir2/test1.txt + PathUtil.moveContent( + FileUtil.file("d:/test/dir1/test1.txt").toPath(), + FileUtil.file("d:/test/dir2").toPath(), false); + } + @Test @Ignore public void moveDirToDirNotExistTest() { @@ -37,11 +57,31 @@ public class IssueI666HBTest { FileUtil.move(FileUtil.file("d:/test/dir1"), FileUtil.file("d:/test/dir3"), false); } + @Test + @Ignore + public void moveContentDirToDirNotExistTest() { + // 目录移动到目标,dir3不存在 + // 会将目录dir1内容移动到dir3,但是dir1目录不删除 + PathUtil.moveContent( + FileUtil.file("d:/test/dir1").toPath(), + FileUtil.file("d:/test/dir3").toPath(), false); + } + @Test @Ignore public void moveFileToTargetNotExistTest() { - // 目录移动到目录,将整个目录移动 + // 文件移动到不存在的路径 // 会将test1.txt重命名为test2 FileUtil.move(FileUtil.file("d:/test/dir1/test1.txt"), FileUtil.file("d:/test/test2"), false); } + + @Test + @Ignore + public void moveContentFileToTargetNotExistTest() { + // 目录移动到目录,将整个目录移动 + // 会将test1.txt重命名为test2 + PathUtil.moveContent( + FileUtil.file("d:/test/dir1/test1.txt").toPath(), + FileUtil.file("d:/test/test2").toPath(), false); + } }