add method

This commit is contained in:
Looly 2022-02-07 17:51:53 +08:00
parent 03c491b963
commit bbb12fa22d
3 changed files with 33 additions and 17 deletions

View File

@ -17,6 +17,7 @@
* 【core 】 CharSequenceUtil增加replace重载(issue#2122@Github) * 【core 】 CharSequenceUtil增加replace重载(issue#2122@Github)
* 【core 】 IntMap和LongMap使用位运算快速求解取余运算(pr#2123@Github) * 【core 】 IntMap和LongMap使用位运算快速求解取余运算(pr#2123@Github)
* 【core 】 新增通用builder类GenericBuilder(pr#526@Gitee) * 【core 】 新增通用builder类GenericBuilder(pr#526@Gitee)
* 【core 】 新增copySafely方法与mkdirsSafely方法(pr#527@Gitee)
### 🐞Bug修复 ### 🐞Bug修复
* 【core 】 修复ChineseDate农历获取正月出现数组越界BUGissue#2112@Github * 【core 】 修复ChineseDate农历获取正月出现数组越界BUGissue#2112@Github

View File

@ -527,26 +527,39 @@ public class FileUtil extends PathUtil {
/** /**
* 计算目录或文件的总大小<br> * 计算目录或文件的总大小<br>
* 当给定对象为文件时直接调用 {@link File#length()}<br> * 当给定对象为文件时直接调用 {@link File#length()}<br>
* 当给定对象为目录时遍历目录下的所有文件和目录递归计算其大小求和返回 * 当给定对象为目录时遍历目录下的所有文件和目录递归计算其大小求和返回<br>
* 此方法不包括目录本身的占用空间大小
* *
* @param file 目录或文件,null或者文件不存在返回0 * @param file 目录或文件,null或者文件不存在返回0
* @return 总大小bytes长度 * @return 总大小bytes长度
*/ */
public static long size(File file) { public static long size(File file) {
return size(file, false);
}
/**
* 计算目录或文件的总大小<br>
* 当给定对象为文件时直接调用 {@link File#length()}<br>
* 当给定对象为目录时遍历目录下的所有文件和目录递归计算其大小求和返回
*
* @param file 目录或文件,null或者文件不存在返回0
* @param includeDirSize 是否包括每层目录本身的大小
* @return 总大小bytes长度
* @since 5.7.21
*/
public static long size(File file, boolean includeDirSize) {
if (null == file || false == file.exists() || isSymlink(file)) { if (null == file || false == file.exists() || isSymlink(file)) {
return 0; return 0;
} }
if (file.isDirectory()) { if (file.isDirectory()) {
// TODO 是否需要统计目录本身的大小呢 long size = includeDirSize ? file.length() : 0;
// size += file.length();
long size = 0L;
File[] subFiles = file.listFiles(); File[] subFiles = file.listFiles();
if (ArrayUtil.isEmpty(subFiles)) { if (ArrayUtil.isEmpty(subFiles)) {
return 0L;// empty directory return 0L;// empty directory
} }
for (File subFile : subFiles) { for (File subFile : subFiles) {
size += size(subFile); size += size(subFile, includeDirSize);
} }
return size; return size;
} else { } else {
@ -610,7 +623,6 @@ public class FileUtil extends PathUtil {
return null; return null;
} }
if (false == file.exists()) { if (false == file.exists()) {
// TODO: {@see mkdirsSafely} 确保并发环境下的安全创建
mkParentDirs(file); mkParentDirs(file);
try { try {
//noinspection ResultOfMethodCallIgnored //noinspection ResultOfMethodCallIgnored
@ -815,7 +827,7 @@ public class FileUtil extends PathUtil {
/** /**
* 创建文件夹会递归自动创建其不存在的父文件夹如果存在直接返回此文件夹<br> * 创建文件夹会递归自动创建其不存在的父文件夹如果存在直接返回此文件夹<br>
* 此方法不对File对象类型做判断如果File不存在无法判断其类型 * 此方法不对File对象类型做判断如果File不存在无法判断其类型<br>
* *
* @param dir 目录 * @param dir 目录
* @return 创建的目录 * @return 创建的目录
@ -825,8 +837,7 @@ public class FileUtil extends PathUtil {
return null; return null;
} }
if (false == dir.exists()) { if (false == dir.exists()) {
//noinspection ResultOfMethodCallIgnored mkdirsSafely(dir, 5, 1);
dir.mkdirs();
} }
return dir; return dir;
} }
@ -843,23 +854,27 @@ public class FileUtil extends PathUtil {
* </pre> * </pre>
* *
* @param dir 待创建的目录 * @param dir 待创建的目录
* @param tryCount 最大尝试次数
* @param sleepMillis 线程等待的毫秒数
* @return true表示创建成功false表示创建失败 * @return true表示创建成功false表示创建失败
* @since 2022-01-29 * @since 5.7.21
* @author z8g * @author z8g
*/ */
public static boolean mkdirsSafely(File dir) { public static boolean mkdirsSafely(File dir, int tryCount, long sleepMillis) {
if (dir == null) { if (dir == null) {
return false; return false;
} }
if (dir.isDirectory()) { if (dir.isDirectory()) {
return true; return true;
} }
for (int i = 1; i <= 5; i++) { // 高并发场景下可以看到 i 处于 1 ~ 3 之间 for (int i = 1; i <= tryCount; i++) { // 高并发场景下可以看到 i 处于 1 ~ 3 之间
dir.mkdirs(); // 如果文件已存在也会返回 false所以该值不能作为是否能创建的依据因此不对其进行处理 // 如果文件已存在也会返回 false所以该值不能作为是否能创建的依据因此不对其进行处理
//noinspection ResultOfMethodCallIgnored
dir.mkdirs();
if (dir.exists()) { if (dir.exists()) {
return true; return true;
} }
ThreadUtil.sleep(1); ThreadUtil.sleep(sleepMillis);
} }
return dir.exists(); return dir.exists();
} }

View File

@ -117,13 +117,13 @@ public class NioUtil {
* @link http://androidxref.com/6.0.1_r10/xref/libcore/luni/src/main/java/java/nio/FileChannelImpl.java * @link http://androidxref.com/6.0.1_r10/xref/libcore/luni/src/main/java/java/nio/FileChannelImpl.java
* @link http://androidxref.com/7.0.0_r1/xref/libcore/ojluni/src/main/java/sun/nio/ch/FileChannelImpl.java * @link http://androidxref.com/7.0.0_r1/xref/libcore/ojluni/src/main/java/sun/nio/ch/FileChannelImpl.java
* @link http://androidxref.com/7.0.0_r1/xref/libcore/ojluni/src/main/native/FileChannelImpl.c * @link http://androidxref.com/7.0.0_r1/xref/libcore/ojluni/src/main/native/FileChannelImpl.c
* @since 2022-01-29
* @author z8g * @author z8g
* @since 5.7.21
*/ */
private static long copySafely(FileChannel inChannel, FileChannel outChannel) throws IOException { private static long copySafely(FileChannel inChannel, FileChannel outChannel) throws IOException {
long totalBytes = inChannel.size(); final long totalBytes = inChannel.size();
for (long pos = 0, remaining = totalBytes; remaining > 0; ) { // 确保文件内容不会缺失 for (long pos = 0, remaining = totalBytes; remaining > 0; ) { // 确保文件内容不会缺失
long writeBytes = inChannel.transferTo(pos, remaining, outChannel); // 实际传输的字节数 final long writeBytes = inChannel.transferTo(pos, remaining, outChannel); // 实际传输的字节数
pos += writeBytes; pos += writeBytes;
remaining -= writeBytes; remaining -= writeBytes;
} }