fix copy #I2CKTI

This commit is contained in:
Looly
2021-01-09 18:51:40 +08:00
parent bab6ab5a27
commit 49fab3986f
5 changed files with 112 additions and 22 deletions

View File

@@ -3,10 +3,11 @@
------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------
# 5.5.8 (2021-01-08) # 5.5.8 (2021-01-09)
### 新特性 ### 新特性
### Bug修复 ### Bug修复
* 【core 】 修复FileUtil.move以及PathUtil.copy等无法自动创建父目录的问题issue#I2CKTI@Gitee
------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------
@@ -29,7 +30,7 @@
* 【core 】 修复CsvReader读取双引号未转义问题issue#I2BMP1@Gitee * 【core 】 修复CsvReader读取双引号未转义问题issue#I2BMP1@Gitee
* 【json 】 JSONUtil.parse修复config无效问题issue#1363@Github * 【json 】 JSONUtil.parse修复config无效问题issue#1363@Github
* 【http 】 修复SimpleServer返回响应内容Content-Length不正确的问题issue#1358@Github * 【http 】 修复SimpleServer返回响应内容Content-Length不正确的问题issue#1358@Github
* 【http 】 修复Https请求部分环境下报证书验证异常问题issue#I2C1BZ@Github * 【http 】 修复Https请求部分环境下报证书验证异常问题issue#I2C1BZ@Gitee
------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------

View File

@@ -638,12 +638,10 @@ public class FileUtil extends PathUtil {
* @return 父目录 * @return 父目录
*/ */
public static File mkParentDirs(File file) { public static File mkParentDirs(File file) {
final File parentFile = file.getParentFile(); if(null == file){
if (null != parentFile && false == parentFile.exists()) { return null;
//noinspection ResultOfMethodCallIgnored
parentFile.mkdirs();
} }
return parentFile; return mkdir(file.getParentFile());
} }
/** /**
@@ -1022,6 +1020,7 @@ public class FileUtil extends PathUtil {
* @param isOverride 是否覆盖目标文件 * @param isOverride 是否覆盖目标文件
* @return 目标文件 * @return 目标文件
* @since 3.0.9 * @since 3.0.9
* @see PathUtil#rename(Path, String, boolean)
*/ */
public static File rename(File file, String newName, boolean isRetainExt, boolean isOverride) { public static File rename(File file, String newName, boolean isRetainExt, boolean isOverride) {
if (isRetainExt) { if (isRetainExt) {
@@ -3192,6 +3191,12 @@ public class FileUtil extends PathUtil {
contentType = "application/x-javascript"; contentType = "application/x-javascript";
} }
} }
// 补充
if(null == contentType){
contentType = getMimeType(Paths.get(filePath));
}
return contentType; return contentType;
} }

View File

@@ -153,7 +153,8 @@ public class PathUtil {
} }
/** /**
* 通过JDK7+的 {@link Files#copy(Path, Path, CopyOption...)} 方法拷贝文件 * 通过JDK7+的 {@link Files#copy(Path, Path, CopyOption...)} 方法拷贝文件<br>
* 此方法不支持递归拷贝目录如果src传入是目录只会在目标目录中创建空目录
* *
* @param src 源文件路径,如果为目录只在目标中创建新目录 * @param src 源文件路径,如果为目录只在目标中创建新目录
* @param dest 目标文件或目录,如果为目录使用与源文件相同的文件名 * @param dest 目标文件或目录,如果为目录使用与源文件相同的文件名
@@ -166,7 +167,8 @@ public class PathUtil {
} }
/** /**
* 通过JDK7+的 {@link Files#copy(Path, Path, CopyOption...)} 方法拷贝文件 * 通过JDK7+的 {@link Files#copy(Path, Path, CopyOption...)} 方法拷贝文件<br>
* 此方法不支持递归拷贝目录如果src传入是目录只会在目标目录中创建空目录
* *
* @param src 源文件路径,如果为目录只在目标中创建新目录 * @param src 源文件路径,如果为目录只在目标中创建新目录
* @param target 目标文件或目录,如果为目录使用与源文件相同的文件名 * @param target 目标文件或目录,如果为目录使用与源文件相同的文件名
@@ -180,6 +182,8 @@ public class PathUtil {
Assert.notNull(target, "Destination File or directiory is null !"); Assert.notNull(target, "Destination File or directiory is null !");
final Path targetPath = isDirectory(target) ? target.resolve(src.getFileName()) : target; final Path targetPath = isDirectory(target) ? target.resolve(src.getFileName()) : target;
// 创建级联父目录
mkParentDirs(targetPath);
try { try {
return Files.copy(src, targetPath, options); return Files.copy(src, targetPath, options);
} catch (IOException e) { } catch (IOException e) {
@@ -188,9 +192,15 @@ public class PathUtil {
} }
/** /**
* 拷贝文件或目录 * 拷贝文件或目录,拷贝规则为:
* *
* @param src 源文件路径,如果为目录只在目标中创建新目录 * <ul>
* <li>源文件为目录,目标也为目录或不存在,则拷贝整个目录到目标目录下</li>
* <li>源文件为文件,目标为目录或不存在,则拷贝文件到目标目录下</li>
* <li>源文件为文件,目标也为文件,则在{@link StandardCopyOption#REPLACE_EXISTING}情况下覆盖之</li>
* </ul>
*
* @param src 源文件路径,如果为目录会在目标中创建新目录
* @param target 目标文件或目录,如果为目录使用与源文件相同的文件名 * @param target 目标文件或目录,如果为目录使用与源文件相同的文件名
* @param options {@link StandardCopyOption} * @param options {@link StandardCopyOption}
* @return Path * @return Path
@@ -198,17 +208,21 @@ public class PathUtil {
* @since 5.5.1 * @since 5.5.1
*/ */
public static Path copy(Path src, Path target, CopyOption... options) throws IORuntimeException { public static Path copy(Path src, Path target, CopyOption... options) throws IORuntimeException {
if (isFile(src, false)) { if (isDirectory(src)) {
return copyFile(src, target, options); return copyContent(src, target.resolve(src.getFileName()), options);
} }
return copyContent(src, target.resolve(src.getFileName()), options); return copyFile(src, target, options);
} }
/** /**
* 拷贝目录下的所有文件或目录到目标目录中 * 拷贝目录下的所有文件或目录到目标目录中,此方法不支持文件对文件的拷贝。
* <ul>
* <li>源文件为目录,目标也为目录或不存在,则拷贝目录下所有文件和目录到目标目录下</li>
* <li>源文件为文件,目标为目录或不存在,则拷贝文件到目标目录下</li>
* </ul>
* *
* @param src 源文件路径,如果为目录只在目标中创建新目录 * @param src 源文件路径,如果为目录只在目标中创建新目录
* @param target 目标文件或目录,如果为目录使用与源文件相同的文件名 * @param target 目标目录,如果为目录使用与源文件相同的文件名
* @param options {@link StandardCopyOption} * @param options {@link StandardCopyOption}
* @return Path * @return Path
* @throws IORuntimeException IO异常 * @throws IORuntimeException IO异常
@@ -450,6 +464,8 @@ public class PathUtil {
if (isDirectory(target)) { if (isDirectory(target)) {
target = target.resolve(src.getFileName()); target = target.resolve(src.getFileName());
} }
// 自动创建目标的父目录
mkParentDirs(target);
try { try {
return Files.move(src, target, options); return Files.move(src, target, options);
} catch (IOException e) { } catch (IOException e) {
@@ -546,6 +562,7 @@ public class PathUtil {
* @param file 文件 * @param file 文件
* @return MimeType * @return MimeType
* @since 5.5.5 * @since 5.5.5
* @see Files#probeContentType(Path)
*/ */
public static String getMimeType(Path file) { public static String getMimeType(Path file) {
try { try {
@@ -554,4 +571,33 @@ public class PathUtil {
throw new IORuntimeException(e); throw new IORuntimeException(e);
} }
} }
/**
* 创建所给目录及其父目录
*
* @param dir 目录
* @return 目录
* @since 5.5.7
*/
public static Path mkdir(Path dir) {
if (null != dir && false == exists(dir, false)) {
try {
Files.createDirectories(dir);
} catch (IOException e) {
throw new IORuntimeException(e);
}
}
return dir;
}
/**
* 创建所给文件或目录的父目录
*
* @param path 文件或目录
* @return 父目录
* @since 5.5.7
*/
public static Path mkParentDirs(Path path) {
return mkdir(path.getParent());
}
} }

View File

@@ -1,5 +1,7 @@
package cn.hutool.core.io.file.visitor; package cn.hutool.core.io.file.visitor;
import cn.hutool.core.io.file.PathUtil;
import java.io.IOException; import java.io.IOException;
import java.nio.file.FileAlreadyExistsException; import java.nio.file.FileAlreadyExistsException;
import java.nio.file.FileVisitResult; import java.nio.file.FileVisitResult;
@@ -9,17 +11,28 @@ import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.BasicFileAttributes;
/** /**
* 文件拷贝的FileVisitor实现用于递归遍历拷贝目录 * 文件拷贝的FileVisitor实现用于递归遍历拷贝目录,此类非线程安全<br>
* 此类在遍历源目录并复制过程中会自动创建目标目录中不存在的上级目录。
* *
* @author looly * @author looly
* @since 5.5.1 * @since 5.5.1
*/ */
public class CopyVisitor extends SimpleFileVisitor<Path> { public class CopyVisitor extends SimpleFileVisitor<Path> {
final Path source; private final Path source;
final Path target; private final Path target;
private boolean isTargetCreated;
/**
* 构造
*
* @param source 源Path
* @param target 目标Path
*/
public CopyVisitor(Path source, Path target) { public CopyVisitor(Path source, Path target) {
if(PathUtil.exists(target, false) && false == PathUtil.isDirectory(target)){
throw new IllegalArgumentException("Target must be a directory");
}
this.source = source; this.source = source;
this.target = target; this.target = target;
} }
@@ -27,11 +40,13 @@ public class CopyVisitor extends SimpleFileVisitor<Path> {
@Override @Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
throws IOException { throws IOException {
initTarget();
// 将当前目录相对于源路径转换为相对于目标路径
final Path targetDir = target.resolve(source.relativize(dir)); final Path targetDir = target.resolve(source.relativize(dir));
try { try {
Files.copy(dir, targetDir); Files.copy(dir, targetDir);
} catch (FileAlreadyExistsException e) { } catch (FileAlreadyExistsException e) {
if (!Files.isDirectory(targetDir)) if (false == Files.isDirectory(targetDir))
throw e; throw e;
} }
return FileVisitResult.CONTINUE; return FileVisitResult.CONTINUE;
@@ -40,7 +55,18 @@ public class CopyVisitor extends SimpleFileVisitor<Path> {
@Override @Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
throws IOException { throws IOException {
initTarget();
Files.copy(file, target.resolve(source.relativize(file))); Files.copy(file, target.resolve(source.relativize(file)));
return FileVisitResult.CONTINUE; return FileVisitResult.CONTINUE;
} }
/**
* 初始化目标文件或目录
*/
private void initTarget(){
if(false == this.isTargetCreated){
PathUtil.mkdir(this.target);
this.isTargetCreated = true;
}
}
} }

View File

@@ -25,7 +25,16 @@ public class PathUtilTest {
public void copyTest(){ public void copyTest(){
PathUtil.copy( PathUtil.copy(
Paths.get("d:/Red2_LYY"), Paths.get("d:/Red2_LYY"),
Paths.get("d:/test/") Paths.get("d:/test/aaa/aaa.txt")
);
}
@Test
@Ignore
public void copyContentTest(){
PathUtil.copyContent(
Paths.get("d:/Red2_LYY"),
Paths.get("d:/test/aaa/")
); );
} }
@@ -37,7 +46,10 @@ public class PathUtilTest {
@Test @Test
public void getMimeTypeTest(){ public void getMimeTypeTest(){
final String mimeType = PathUtil.getMimeType(Paths.get("d:/test/test.jpg")); String mimeType = PathUtil.getMimeType(Paths.get("d:/test/test.jpg"));
Assert.assertEquals("image/jpeg", mimeType); Assert.assertEquals("image/jpeg", mimeType);
mimeType = PathUtil.getMimeType(Paths.get("d:/test/test.mov"));
Assert.assertEquals("video/quicktime", mimeType);
} }
} }