This commit is contained in:
Looly 2019-09-19 10:15:04 +08:00
parent 4d46555b2d
commit 04830bf06b

View File

@ -32,14 +32,7 @@ import java.nio.file.SimpleFileVisitor;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.EnumSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import java.util.jar.JarFile;
import java.util.regex.Pattern;
import java.util.zip.CRC32;
@ -68,24 +61,37 @@ import cn.hutool.core.util.ZipUtil;
* 文件工具类
*
* @author xiaoleilu
*
*/
public class FileUtil {
/** 类Unix路径分隔符 */
/**
* 类Unix路径分隔符
*/
private static final char UNIX_SEPARATOR = CharUtil.SLASH;
/** Windows路径分隔符 */
/**
* Windows路径分隔符
*/
private static final char WINDOWS_SEPARATOR = CharUtil.BACKSLASH;
/** Windows下文件名中的无效字符 */
/**
* Windows下文件名中的无效字符
*/
private static Pattern FILE_NAME_INVALID_PATTERN_WIN = Pattern.compile("[\\\\/:*?\"<>|]");
/** Class文件扩展名 */
/**
* Class文件扩展名
*/
public static final String CLASS_EXT = ".class";
/** Jar文件扩展名 */
/**
* Jar文件扩展名
*/
public static final String JAR_FILE_EXT = ".jar";
/** 在Jar中的路径jar的扩展名形式 */
/**
* 在Jar中的路径jar的扩展名形式
*/
public static final String JAR_PATH_EXT = ".jar!";
/** 当Path为文件形式时, path会加入一个表示文件的前缀 */
/**
* 当Path为文件形式时, path会加入一个表示文件的前缀
*/
public static final String PATH_FILE_PRE = URLUtil.FILE_URL_PREFIX;
/**
@ -131,9 +137,7 @@ public class FileUtil {
if (file.isDirectory()) {
String[] subFiles = file.list();
if (ArrayUtil.isEmpty(subFiles)) {
return true;
}
return ArrayUtil.isEmpty(subFiles);
} else if (file.isFile()) {
return file.length() <= 0;
}
@ -156,7 +160,7 @@ public class FileUtil {
*
* @param dirPath 目录
* @return 是否为空
* @exception IORuntimeException IOException
* @throws IORuntimeException IOException
*/
public static boolean isDirEmpty(Path dirPath) {
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(dirPath)) {
@ -198,7 +202,7 @@ public class FileUtil {
* @return 文件列表
*/
public static List<File> loopFiles(File file, FileFilter fileFilter) {
final List<File> fileList = new ArrayList<File>();
final List<File> fileList = new ArrayList<>();
if (null == file || false == file.exists()) {
return fileList;
}
@ -243,7 +247,7 @@ public class FileUtil {
walkFiles(file.toPath(), maxDepth, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException {
public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) {
final File file = path.toFile();
if (null == fileFilter || fileFilter.accept(file)) {
fileList.add(file);
@ -261,8 +265,8 @@ public class FileUtil {
* @param start 起始路径必须为目录
* @param maxDepth 最大遍历深度-1表示不限制深度
* @param visitor {@link FileVisitor} 接口用于自定义在访问文件时访问目录前后等节点做的操作
* @since 4.6.3
* @see Files#walkFileTree(Path, Set, int, FileVisitor)
* @since 4.6.3
*/
public static void walkFiles(Path start, int maxDepth, FileVisitor<? super Path> visitor) {
if (maxDepth < 0) {
@ -415,7 +419,7 @@ public class FileUtil {
/**
* 通过多层目录创建文件
*
* <p>
* 元素名多层目录名
*
* @return the file 文件
@ -507,7 +511,7 @@ public class FileUtil {
* @return 如果存在返回true
*/
public static boolean exist(String path) {
return (path == null) ? false : file(path).exists();
return (null != path) && file(path).exists();
}
/**
@ -517,7 +521,7 @@ public class FileUtil {
* @return 如果存在返回true
*/
public static boolean exist(File file) {
return (file == null) ? false : file.exists();
return (null != file) && file.exists();
}
/**
@ -833,6 +837,7 @@ public class FileUtil {
}
final File[] files = directory.listFiles();
if (null != files) {
boolean isOk;
for (File childFile : files) {
isOk = del(childFile);
@ -841,6 +846,7 @@ public class FileUtil {
return false;
}
}
}
return true;
}
@ -863,10 +869,11 @@ public class FileUtil {
if (ArrayUtil.isEmpty(files)) {
// 空文件夹则删除之
directory.delete();
}
} else {
for (File childFile : files) {
cleanEmpty(childFile);
}
}
return true;
}
@ -1137,7 +1144,7 @@ public class FileUtil {
* <pre>
* FileUtil.rename(file, "aaa", true) xx/xx.png =xx/aaa.png
* </pre>
*
* <p>
* 2isRetainExt为false时不保留原扩展名需要在newName中
*
* <pre>
@ -1218,7 +1225,7 @@ public class FileUtil {
}
// 资源不存在的情况下使用标准化路径有问题使用原始路径拼接后标准化路径
return normalize(classPath.concat(path));
return normalize(classPath.concat(Objects.requireNonNull(path)));
}
/**
@ -1263,11 +1270,8 @@ public class FileUtil {
return false;
}
if (StrUtil.C_SLASH == path.charAt(0) || path.matches("^[a-zA-Z]:[/\\\\].*")) {
// 给定的路径已经是绝对路径了
return true;
}
return false;
return StrUtil.C_SLASH == path.charAt(0) || path.matches("^[a-zA-Z]:[/\\\\].*");
}
/**
@ -1277,7 +1281,7 @@ public class FileUtil {
* @return 如果为目录true
*/
public static boolean isDirectory(String path) {
return (path == null) ? false : file(path).isDirectory();
return (null != path) && file(path).isDirectory();
}
/**
@ -1287,7 +1291,7 @@ public class FileUtil {
* @return 如果为目录true
*/
public static boolean isDirectory(File file) {
return (file == null) ? false : file.isDirectory();
return (null != file) && file.isDirectory();
}
/**
@ -1313,7 +1317,7 @@ public class FileUtil {
* @return 如果为文件true
*/
public static boolean isFile(String path) {
return (path == null) ? false : file(path).isFile();
return (null != path) && file(path).isFile();
}
/**
@ -1323,7 +1327,7 @@ public class FileUtil {
* @return 如果为文件true
*/
public static boolean isFile(File file) {
return (file == null) ? false : file.isFile();
return (null != file) && file.isFile();
}
/**
@ -1355,12 +1359,10 @@ public class FileUtil {
Assert.notNull(file1);
Assert.notNull(file2);
if (false == file1.exists() || false == file2.exists()) {
// 两个文件都不存在判断其路径是否相同
if (false == file1.exists() && false == file2.exists() && pathEquals(file1, file2)) {
return true;
}
// 对于一个存在一个不存在的情况一定不相同
return false;
// 两个文件都不存在判断其路径是否相同 对于一个存在一个不存在的情况一定不相同
return false == file1.exists()//
&& false == file2.exists()//
&& pathEquals(file1, file2);
}
try {
return Files.isSameFile(file1.toPath(), file2.toPath());
@ -1420,6 +1422,7 @@ public class FileUtil {
}
// -----------------------------------------------------------------------
/**
* 比较两个文件内容是否相同<br>
* 首先比较长度长度一致再比较内容比较内容采用按行读取每行比较<br>
@ -1544,7 +1547,7 @@ public class FileUtil {
* <li>3. 去除两边空格</li>
* <li>4. .. . 转换为绝对路径..多于已有路径时直接返回根路径</li>
* </ol>
*
* <p>
* 栗子
*
* <pre>
@ -1602,15 +1605,15 @@ public class FileUtil {
}
List<String> pathList = StrUtil.split(pathToUse, StrUtil.C_SLASH);
List<String> pathElements = new LinkedList<String>();
List<String> pathElements = new LinkedList<>();
int tops = 0;
String element;
for (int i = pathList.size() - 1; i >= 0; i--) {
element = pathList.get(i);
if (StrUtil.DOT.equals(element)) {
// 当前目录丢弃
} else if (StrUtil.DOUBLE_DOT.equals(element)) {
// 只处理非.的目录既只处理非当前目录
if (false == StrUtil.DOT.equals(element)) {
if (StrUtil.DOUBLE_DOT.equals(element)) {
tops++;
} else {
if (tops > 0) {
@ -1622,13 +1625,14 @@ public class FileUtil {
}
}
}
}
return prefix + CollUtil.join(pathElements, StrUtil.SLASH);
}
/**
* 获得相对子路径
*
* <p>
* 栗子
*
* <pre>
@ -1650,7 +1654,7 @@ public class FileUtil {
/**
* 获得相对子路径忽略大小写
*
* <p>
* 栗子
*
* <pre>
@ -1744,6 +1748,7 @@ public class FileUtil {
}
// -------------------------------------------------------------------------------------------- name start
/**
* 返回文件名
*
@ -1810,7 +1815,7 @@ public class FileUtil {
*/
public static String mainName(String fileName) {
if (null == fileName) {
return fileName;
return null;
}
int len = fileName.length();
if (0 == len) {
@ -1823,20 +1828,18 @@ public class FileUtil {
int begin = 0;
int end = len;
char c;
for (int i = len - 1; i > -1; i--) {
for (int i = len - 1; i >= 0; i--) {
c = fileName.charAt(i);
if (len == end && CharUtil.DOT == c) {
// 查找最后一个文件名和扩展名的分隔符.
end = i;
}
if (0 == begin || begin > end) {
if (CharUtil.isFileSeparator(c)) {
// 查找最后一个路径分隔符/或者\如果这个分隔符在.之后则继续查找否则结束
if (CharUtil.isFileSeparator(c)) {
begin = i + 1;
break;
}
}
}
return fileName.substring(begin, end);
}
@ -1893,11 +1896,10 @@ public class FileUtil {
/**
* 根据文件流的头部信息获得文件类型
*
* @see FileTypeUtil#getType(File)
*
* @param file 文件 {@link File}
* @return 类型文件的扩展名未找到为<code>null</code>
* @throws IORuntimeException IO异常
* @see FileTypeUtil#getType(File)
*/
public static String getType(File file) throws IORuntimeException {
return FileTypeUtil.getType(file);
@ -1926,6 +1928,7 @@ public class FileUtil {
}
// -------------------------------------------------------------------------------------------- in start
/**
* 获得输入流
*
@ -2470,7 +2473,7 @@ public class FileUtil {
* @since 4.5.2
*/
public static void readLines(RandomAccessFile file, Charset charset, LineHandler lineHandler) {
String line = null;
String line;
try {
while ((line = file.readLine()) != null) {
lineHandler.handle(CharsetUtil.convert(line, CharsetUtil.CHARSET_ISO_8859_1, charset));
@ -2506,7 +2509,7 @@ public class FileUtil {
* @since 4.5.18
*/
public static String readLine(RandomAccessFile file, Charset charset) {
String line = null;
String line;
try {
line = file.readLine();
} catch (IOException e) {
@ -2609,6 +2612,7 @@ public class FileUtil {
}
// -------------------------------------------------------------------------------------------- out start
/**
* 获得一个输出流对象
*
@ -2799,7 +2803,6 @@ public class FileUtil {
/**
* 将String写入文件覆盖模式
*
*
* @param content 写入的内容
* @param file 文件
* @param charset 字符集
@ -2813,7 +2816,6 @@ public class FileUtil {
/**
* 将String写入文件覆盖模式
*
*
* @param content 写入的内容
* @param file 文件
* @param charset 字符集
@ -3326,7 +3328,7 @@ public class FileUtil {
* @since 3.3.1
*/
public static boolean containsInvalid(String fileName) {
return StrUtil.isBlank(fileName) ? false : ReUtil.contains(FILE_NAME_INVALID_PATTERN_WIN, fileName);
return (false == StrUtil.isBlank(fileName)) && ReUtil.contains(FILE_NAME_INVALID_PATTERN_WIN, fileName);
}
/**