mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-07-21 15:09:48 +08:00
fix copy #I2CKTI
This commit is contained in:
@@ -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)
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user