diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/io/file/FileUtil.java b/hutool-core/src/main/java/org/dromara/hutool/core/io/file/FileUtil.java
index 7c41eaf77..ad6b417e9 100644
--- a/hutool-core/src/main/java/org/dromara/hutool/core/io/file/FileUtil.java
+++ b/hutool-core/src/main/java/org/dromara/hutool/core/io/file/FileUtil.java
@@ -19,6 +19,8 @@ import org.dromara.hutool.core.func.SerFunction;
import org.dromara.hutool.core.io.BomReader;
import org.dromara.hutool.core.io.IORuntimeException;
import org.dromara.hutool.core.io.IoUtil;
+import org.dromara.hutool.core.io.resource.FileResource;
+import org.dromara.hutool.core.io.resource.Resource;
import org.dromara.hutool.core.io.resource.ResourceUtil;
import org.dromara.hutool.core.io.stream.BOMInputStream;
import org.dromara.hutool.core.io.unit.DataSizeUtil;
@@ -214,7 +216,7 @@ public class FileUtil extends PathUtil {
*
* 此方法与{@link #loopFiles(File, FileFilter)}不同的是,处理目录判断,可减少无效目录的遍历。
*
- * @param file 文件或目录,文件直接处理
+ * @param file 文件或目录,文件直接处理
* @param predicate 文件处理器,只会处理文件
* @since 5.5.2
*/
@@ -911,6 +913,31 @@ public class FileUtil extends PathUtil {
}
// endregion
+ // region ----- copy
+
+ /**
+ * 拷贝资源到目标文件
+ *
+ * - 如果src为{@link FileResource},调用文件拷贝。
+ * - 其它,调用JDK7+的 {@link Files#copy(InputStream, Path, CopyOption...)}。
+ *
+ *
+ * @param src 源文件
+ * @param target 目标文件或目录,目标不存在会自动创建(目录、文件都创建)
+ * @param isOverride 是否覆盖目标文件
+ * @return 目标目录或文件
+ * @throws IORuntimeException IO异常
+ */
+ public static File copy(final Resource 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 copy(
+ src,
+ target.toPath(),
+ isOverride ? new CopyOption[]{StandardCopyOption.REPLACE_EXISTING} : new CopyOption[]{})
+ .toFile();
+ }
+
/**
* 复制文件或目录
* 如果目标文件为目录,则将源文件以相同文件名拷贝到目标目录
@@ -976,6 +1003,7 @@ public class FileUtil extends PathUtil {
isOverride ? new CopyOption[]{StandardCopyOption.REPLACE_EXISTING} : new CopyOption[]{})
.toFile();
}
+ // endregion
/**
* 移动文件或目录到目标中,例如:
@@ -1052,6 +1080,8 @@ public class FileUtil extends PathUtil {
return rename(file.toPath(), newName, isOverride).toFile();
}
+ // region ----- getCanonicalPath and getAbsolutePath
+
/**
* 获取规范的绝对路径
*
@@ -1160,6 +1190,7 @@ public class FileUtil extends PathUtil {
// 给定的路径已经是绝对路径了
return CharUtil.SLASH == path.charAt(0) || ReUtil.isMatch(PATTERN_PATH_ABSOLUTE, path);
}
+ // endregion
/**
* 判断是否为目录,如果path为null,则返回false
@@ -2438,27 +2469,27 @@ public class FileUtil extends PathUtil {
* 将流的内容写入文件
* 此方法会自动关闭输入流
*
- * @param dest 目标文件
- * @param in 输入流
+ * @param target 目标文件
+ * @param in 输入流
* @return dest
* @throws IORuntimeException IO异常
*/
- public static File writeFromStream(final InputStream in, final File dest) throws IORuntimeException {
- return writeFromStream(in, dest, true);
+ public static File writeFromStream(final InputStream in, final File target) throws IORuntimeException {
+ return writeFromStream(in, target, true);
}
/**
* 将流的内容写入文件
*
- * @param dest 目标文件
+ * @param target 目标文件
* @param in 输入流
* @param isCloseIn 是否关闭输入流
* @return dest
* @throws IORuntimeException IO异常
* @since 5.5.6
*/
- public static File writeFromStream(final InputStream in, final File dest, final boolean isCloseIn) throws IORuntimeException {
- return FileWriter.of(dest).writeFromStream(in, isCloseIn);
+ public static File writeFromStream(final InputStream in, final File target, final boolean isCloseIn) throws IORuntimeException {
+ return FileWriter.of(target).writeFromStream(in, isCloseIn);
}
/**
@@ -2506,6 +2537,7 @@ public class FileUtil extends PathUtil {
* @return 大小
*/
public static String readableFileSize(final File file) {
+ Assert.notNull(file);
return readableFileSize(file.length());
}
diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/io/file/PathUtil.java b/hutool-core/src/main/java/org/dromara/hutool/core/io/file/PathUtil.java
index 086156dd8..f320fbe17 100644
--- a/hutool-core/src/main/java/org/dromara/hutool/core/io/file/PathUtil.java
+++ b/hutool-core/src/main/java/org/dromara/hutool/core/io/file/PathUtil.java
@@ -15,6 +15,9 @@ package org.dromara.hutool.core.io.file;
import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.io.IORuntimeException;
import org.dromara.hutool.core.io.IoUtil;
+import org.dromara.hutool.core.io.resource.FileResource;
+import org.dromara.hutool.core.io.resource.Resource;
+import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.util.CharsetUtil;
import java.io.*;
@@ -85,6 +88,7 @@ public class PathUtil {
}
}
+ // region ----- loop and walk
/**
* 递归遍历目录以及子目录中的所有文件
* 如果提供path为文件,直接返回过滤结果
@@ -151,8 +155,6 @@ public class PathUtil {
return fileList;
}
- // region ----- walkFiles
-
/**
* 遍历指定path下的文件并做处理
*
@@ -224,6 +226,74 @@ public class PathUtil {
PathDeleter.of(path).clean();
}
+ // region ----- copy
+ /**
+ * 拷贝资源到目标文件
+ *
+ * - 如果src为{@link FileResource},调用文件拷贝。
+ * - 其它,调用JDK7+的 {@link Files#copy(InputStream, Path, CopyOption...)}。
+ *
+ *
+ * @param src 源文件资源{@link Resource}实现
+ * @param target 目标文件或目录,如果为目录使用与源文件相同的文件名
+ * @param options {@link StandardCopyOption}
+ * @return 目标Path
+ * @throws IORuntimeException IO异常
+ * @since 5.8.27
+ */
+ public static Path copy(final Resource src, final Path target, final CopyOption... options) throws IORuntimeException {
+ Assert.notNull(src, "Source is null !");
+ if (src instanceof FileResource) {
+ return copy(((FileResource) src).getFile().toPath(), target, options);
+ }
+ try (final InputStream stream = src.getStream()) {
+ return copy(stream, target, options);
+ } catch (final IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * 通过JDK7+的 {@link Files#copy(InputStream, Path, CopyOption...)} 方法拷贝文件
+ *
+ * @param src 源文件流,使用后不闭流
+ * @param target 目标文件或目录,如果为目录使用与源文件相同的文件名
+ * @param options {@link StandardCopyOption}
+ * @return 目标Path
+ * @throws IORuntimeException IO异常
+ * @since 5.8.27
+ */
+ public static Path copy(final InputStream src, final Path target, final CopyOption... options) throws IORuntimeException {
+ Assert.notNull(target, "Destination File or directory is null !");
+
+ try {
+ Files.copy(src, target, options);
+ } catch (final IOException e) {
+ throw new IORuntimeException(e);
+ }
+
+ return target;
+ }
+
+ /**
+ * 通过JDK7+的 {@link Files#copy(InputStream, Path, CopyOption...)} 方法拷贝文件
+ *
+ * @param src 源文件流,使用后不闭流
+ * @param target 目标文件或目录,如果为目录使用与源文件相同的文件名
+ * @return 拷贝bytes数
+ * @throws IORuntimeException IO异常
+ * @since 6.0.0
+ */
+ public static long copy(final Path src, final OutputStream target) throws IORuntimeException {
+ Assert.notNull(src, "Source is null !");
+
+ try {
+ return Files.copy(src, target);
+ } catch (final IOException e) {
+ throw new IORuntimeException(e);
+ }
+ }
+
/**
* 复制src到target中
*
@@ -267,6 +337,7 @@ public class PathUtil {
public static Path copyContent(final Path src, final Path target, final CopyOption... options) throws IORuntimeException {
return PathCopier.of(src, target, options).copyContent();
}
+ // endregion
/**
* 判断是否为目录,如果file为null,则返回false