From ea3060cddf8b15282409e2593fc5bca826c719ed Mon Sep 17 00:00:00 2001 From: Looly Date: Sun, 15 Nov 2020 11:15:03 +0800 Subject: [PATCH] fix move bug --- CHANGELOG.md | 1 + .../main/java/cn/hutool/core/io/FileUtil.java | 36 ++-------------- .../cn/hutool/core/io/file/FileCopier.java | 8 ++-- .../java/cn/hutool/core/io/file/PathUtil.java | 41 ++++++++++++++++--- .../java/cn/hutool/core/io/FileUtilTest.java | 6 +++ .../cn/hutool/core/io/file/PathUtilTest.java | 6 +++ .../hutool/poi/excel/test/ExcelReadTest.java | 1 + 7 files changed, 58 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 074560b79..0ca3fa474 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ ### 新特性 ### Bug修复 +* 【core 】 修复在Linux下FileUtil.move失败问题(issue#I254Y3@Gitee) ------------------------------------------------------------------------------------------------------------- diff --git a/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java b/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java index 04f8c5b26..6583e98d2 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java @@ -968,41 +968,13 @@ public class FileUtil extends PathUtil { * 移动文件或者目录 * * @param src 源文件或者目录 - * @param dest 目标文件或者目录 + * @param target 目标文件或者目录 * @param isOverride 是否覆盖目标,只有目标为文件才覆盖 * @throws IORuntimeException IO异常 + * @see PathUtil#move(Path, Path, boolean) */ - public static void move(File src, File dest, boolean isOverride) throws IORuntimeException { - // check - if (false == src.exists()) { - throw new IORuntimeException("File not found: " + src); - } - - // 来源为文件夹,目标为文件 - if (src.isDirectory() && dest.isFile()) { - throw new IORuntimeException(StrUtil.format("Can not move directory [{}] to file [{}]", src, dest)); - } - - if (isOverride && dest.isFile()) {// 只有目标为文件的情况下覆盖之 - //noinspection ResultOfMethodCallIgnored - dest.delete(); - } - - // 来源为文件,目标为文件夹 - if (src.isFile() && dest.isDirectory()) { - dest = new File(dest, src.getName()); - } - - if (false == src.renameTo(dest)) { - // 在文件系统不同的情况下,renameTo会失败,此时使用copy,然后删除原文件 - try { - copy(src, dest, isOverride); - } catch (Exception e) { - throw new IORuntimeException(StrUtil.format("Move [{}] to [{}] failed!", src, dest), e); - } - // 复制后删除源 - del(src); - } + public static void move(File src, File target, boolean isOverride) throws IORuntimeException { + move(src.toPath(), target.toPath(), isOverride); } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/io/file/FileCopier.java b/hutool-core/src/main/java/cn/hutool/core/io/file/FileCopier.java index 25abe5ce1..4fa339681 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/file/FileCopier.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/file/FileCopier.java @@ -44,7 +44,7 @@ public class FileCopier extends SrcToDestCopier{ * 新建一个文件复制器 * @param srcPath 源文件路径(相对ClassPath路径或绝对路径) * @param destPath 目标文件路径(相对ClassPath路径或绝对路径) - * @return {@link FileCopier} + * @return this */ public static FileCopier create(String srcPath, String destPath) { return new FileCopier(FileUtil.file(srcPath), FileUtil.file(destPath)); @@ -54,7 +54,7 @@ public class FileCopier extends SrcToDestCopier{ * 新建一个文件复制器 * @param src 源文件 * @param dest 目标文件 - * @return {@link FileCopier} + * @return this */ public static FileCopier create(File src, File dest) { return new FileCopier(src, dest); @@ -188,8 +188,8 @@ public class FileCopier extends SrcToDestCopier{ throw new IORuntimeException("Dest is a sub directory of src !"); } - final File subDest = isCopyContentIfDir ? dest : FileUtil.mkdir(FileUtil.file(dest, src.getName())); - internalCopyDirContent(src, subDest); + final File subTarget = isCopyContentIfDir ? dest : FileUtil.mkdir(FileUtil.file(dest, src.getName())); + internalCopyDirContent(src, subTarget); } else {// 复制文件 internalCopyFile(src, dest); } 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 c4e5bddd2..567532dc9 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 @@ -66,7 +66,7 @@ public class PathUtil { if (null == path || false == Files.exists(path)) { return fileList; - } else if (false == Files.isDirectory(path)) { + } else if (false == isDirectory(path)) { final File file = path.toFile(); if (null == fileFilter || fileFilter.accept(file)) { fileList.add(file); @@ -112,7 +112,7 @@ public class PathUtil { } /** - * 删除文件或者文件夹
+ * 删除文件或者文件夹,不追踪软链
* 注意:删除文件夹时不会判断文件夹是否为空,如果不空则递归删除子文件或文件夹
* 某个文件删除失败会终止删除操作 * @@ -127,7 +127,7 @@ public class PathUtil { } try { - if (Files.isDirectory(path)) { + if (isDirectory(path)) { Files.walkFileTree(path, new SimpleFileVisitor() { @Override @@ -182,7 +182,7 @@ public class PathUtil { Assert.notNull(src, "Source File is null !"); Assert.notNull(dest, "Destination File or directiory is null !"); - Path destPath = dest.toFile().isDirectory() ? dest.resolve(src.getFileName()) : dest; + Path destPath = isDirectory(dest) ? dest.resolve(src.getFileName()) : dest; try { return Files.copy(src, destPath, options); } catch (IOException e) { @@ -190,6 +190,18 @@ public class PathUtil { } } + /** + * 判断是否为目录,如果file为null,则返回false
+ * 此方法不会追踪到软链对应的真实地址,即软链被当作文件 + * + * @param path {@link Path} + * @return 如果为目录true + * @since 5.5.1 + */ + public static boolean isDirectory(Path path) { + return isDirectory(path, false); + } + /** * 判断是否为目录,如果file为null,则返回false * @@ -370,9 +382,28 @@ public class PathUtil { * @since 5.4.1 */ public static Path rename(Path path, String newName, boolean isOverride) { + return move(path, path.resolveSibling(newName), isOverride); + } + + /** + * 移动文件或目录
+ * 当目标是目录时,会将源文件或文件夹整体移动至目标目录下 + * + * @param src 源文件或目录路径 + * @param target 目标路径,如果为目录,则移动到此目录下 + * @param isOverride 是否覆盖目标文件 + * @return 目标文件Path + * @since 5.5.1 + */ + public static Path move(Path src, Path target, boolean isOverride) { + Assert.notNull(src, "Src path must be not null !"); + Assert.notNull(target, "Target path must be not null !"); final CopyOption[] options = isOverride ? new CopyOption[]{StandardCopyOption.REPLACE_EXISTING} : new CopyOption[]{}; + if (isDirectory(target)) { + target = target.resolve(src.getFileName()); + } try { - return Files.move(path, path.resolveSibling(newName), options); + return Files.move(src, target, options); } catch (IOException e) { throw new IORuntimeException(e); } diff --git a/hutool-core/src/test/java/cn/hutool/core/io/FileUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/io/FileUtilTest.java index db058d3aa..d1f45e077 100644 --- a/hutool-core/src/test/java/cn/hutool/core/io/FileUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/io/FileUtilTest.java @@ -73,6 +73,12 @@ public class FileUtilTest { FileUtil.rename(FileUtil.file("d:/test/3.jpg"), "2.jpg", false); } + @Test + @Ignore + public void renameTest2() { + FileUtil.move(FileUtil.file("d:/test/a"), FileUtil.file("d:/test/b"), false); + } + @Test public void copyTest() { File srcFile = FileUtil.file("hutool.jpg"); diff --git a/hutool-core/src/test/java/cn/hutool/core/io/file/PathUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/io/file/PathUtilTest.java index 0fed2a0a3..2d5b14dfd 100644 --- a/hutool-core/src/test/java/cn/hutool/core/io/file/PathUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/io/file/PathUtilTest.java @@ -18,4 +18,10 @@ public class PathUtilTest { StandardCopyOption.REPLACE_EXISTING ); } + + @Test + @Ignore + public void moveTest(){ + PathUtil.move(Paths.get("d:/lombok.jar"), Paths.get("d:/test/"), false); + } } diff --git a/hutool-poi/src/test/java/cn/hutool/poi/excel/test/ExcelReadTest.java b/hutool-poi/src/test/java/cn/hutool/poi/excel/test/ExcelReadTest.java index 459348ec1..1ed8526e1 100644 --- a/hutool-poi/src/test/java/cn/hutool/poi/excel/test/ExcelReadTest.java +++ b/hutool-poi/src/test/java/cn/hutool/poi/excel/test/ExcelReadTest.java @@ -187,6 +187,7 @@ public class ExcelReadTest { } @Test + @Ignore public void readCellsTest() { final ExcelReader reader = ExcelUtil.getReader("merge_test.xlsx"); reader.read((cell, value)-> Console.log("{}, {} {}", cell.getRowIndex(), cell.getColumnIndex(), value));