add dataSize

This commit is contained in:
Looly 2020-07-16 11:56:36 +08:00
parent 84c38aa3f0
commit d70687d20d
6 changed files with 406 additions and 8 deletions

View File

@ -3,10 +3,11 @@
-------------------------------------------------------------------------------------------------------------
## 5.3.10 (2020-07-14)
## 5.3.10 (2020-07-16)
### 新特性
* 【db 】 增加DbUtil.setReturnGeneratedKeyGlobalissue#I1NM0K@Gitee
* 【core 】 增加DataSize和DataSizeUtilissue#967@Github
### Bug修复
* 【core 】 修复ZipUtil中finish位于循环内的问题issue#961@Github

View File

@ -9,6 +9,7 @@ import cn.hutool.core.io.file.FileWriter;
import cn.hutool.core.io.file.LineSeparator;
import cn.hutool.core.io.file.Tailer;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.io.unit.DataSizeUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.CharUtil;
@ -50,7 +51,6 @@ import java.nio.file.Paths;
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;
@ -3361,14 +3361,10 @@ public class FileUtil {
*
* @param size Long类型大小
* @return 大小
* @see DataSizeUtil#format(long)
*/
public static String readableFileSize(long size) {
if (size <= 0) {
return "0";
}
final String[] units = new String[]{"B", "kB", "MB", "GB", "TB", "EB"};
int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
return new DecimalFormat("#,##0.##").format(size / Math.pow(1024, digitGroups)) + " " + units[digitGroups];
return DataSizeUtil.format(size);
}
/**

View File

@ -0,0 +1,277 @@
package cn.hutool.core.io.unit;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 数据大小可以将类似于'12MB'表示转换为bytes长度的数字
* <p>
* 此类来自于Spring-framework
*
* <p>
* <table border="1">
* <tr><th>Term</th><th>Data Size</th><th>Size in Bytes</th></tr>
* <tr><td>byte</td><td>1B</td><td>1</td></tr>
* <tr><td>kilobyte</td><td>1KB</td><td>1,024</td></tr>
* <tr><td>megabyte</td><td>1MB</td><td>1,048,576</td></tr>
* <tr><td>gigabyte</td><td>1GB</td><td>1,073,741,824</td></tr>
* <tr><td>terabyte</td><td>1TB</td><td>1,099,511,627,776</td></tr>
* </table>
*
* @author Sam Brannen,Stephane Nicoll
* @since 5.3.10
*/
public final class DataSize implements Comparable<DataSize> {
/**
* The pattern for parsing.
*/
private static final Pattern PATTERN = Pattern.compile("^([+\\-]?\\d+)([a-zA-Z]{0,2})$");
/**
* Bytes per Kilobyte(KB).
*/
private static final long BYTES_PER_KB = 1024;
/**
* Bytes per Megabyte(MB).
*/
private static final long BYTES_PER_MB = BYTES_PER_KB * 1024;
/**
* Bytes per Gigabyte(GB).
*/
private static final long BYTES_PER_GB = BYTES_PER_MB * 1024;
/**
* Bytes per Terabyte(TB).
*/
private static final long BYTES_PER_TB = BYTES_PER_GB * 1024;
/**
* bytes长度
*/
private final long bytes;
/**
* 构造
*
* @param bytes 长度
*/
private DataSize(long bytes) {
this.bytes = bytes;
}
/**
* 获得对应bytes的{@link DataSize}
*
* @param bytes bytes大小可正可负
* @return a {@link DataSize}
*/
public static DataSize ofBytes(long bytes) {
return new DataSize(bytes);
}
/**
* 获得对应kilobytes的{@link DataSize}
*
* @param kilobytes kilobytes大小可正可负
* @return a {@link DataSize}
*/
public static DataSize ofKilobytes(long kilobytes) {
return new DataSize(Math.multiplyExact(kilobytes, BYTES_PER_KB));
}
/**
* 获得对应megabytes的{@link DataSize}
*
* @param megabytes megabytes大小可正可负
* @return a {@link DataSize}
*/
public static DataSize ofMegabytes(long megabytes) {
return new DataSize(Math.multiplyExact(megabytes, BYTES_PER_MB));
}
/**
* 获得对应gigabytes的{@link DataSize}
*
* @param gigabytes gigabytes大小可正可负
* @return a {@link DataSize}
*/
public static DataSize ofGigabytes(long gigabytes) {
return new DataSize(Math.multiplyExact(gigabytes, BYTES_PER_GB));
}
/**
* 获得对应terabytes的{@link DataSize}
*
* @param terabytes terabytes大小可正可负
* @return a {@link DataSize}
*/
public static DataSize ofTerabytes(long terabytes) {
return new DataSize(Math.multiplyExact(terabytes, BYTES_PER_TB));
}
/**
* 获得指定{@link DataUnit}对应的{@link DataSize}
*
* @param amount 大小
* @param unit 数据大小单位null表示默认的BYTES
* @return {@link DataSize}
*/
public static DataSize of(long amount, DataUnit unit) {
if(null == unit){
unit = DataUnit.BYTES;
}
return new DataSize(Math.multiplyExact(amount, unit.size().toBytes()));
}
/**
* 获取指定数据大小文本对应的{@link DataSize}对象如果无单位指定默认获取{@link DataUnit#BYTES}
* <p>
* 例如
* <pre>
* "12KB" -- parses as "12 kilobytes"
* "5MB" -- parses as "5 megabytes"
* "20" -- parses as "20 bytes"
* </pre>
*
* @param text the text to parse
* @return the parsed {@link DataSize}
* @see #parse(CharSequence, DataUnit)
*/
public static DataSize parse(CharSequence text) {
return parse(text, null);
}
/**
* Obtain a {@link DataSize} from a text string such as {@code 12MB} using
* the specified default {@link DataUnit} if no unit is specified.
* <p>
* The string starts with a number followed optionally by a unit matching one of the
* supported {@linkplain DataUnit suffixes}.
* <p>
* Examples:
* <pre>
* "12KB" -- parses as "12 kilobytes"
* "5MB" -- parses as "5 megabytes"
* "20" -- parses as "20 kilobytes" (where the {@code defaultUnit} is {@link DataUnit#KILOBYTES})
* </pre>
*
* @param text the text to parse
* @return the parsed {@link DataSize}
*/
public static DataSize parse(CharSequence text, DataUnit defaultUnit) {
Assert.notNull(text, "Text must not be null");
try {
Matcher matcher = PATTERN.matcher(text);
Assert.state(matcher.matches(), "Does not match data size pattern");
DataUnit unit = determineDataUnit(matcher.group(2), defaultUnit);
long amount = Long.parseLong(matcher.group(1));
return DataSize.of(amount, unit);
} catch (Exception ex) {
throw new IllegalArgumentException("'" + text + "' is not a valid data size", ex);
}
}
/**
* 决定数据单位后缀不识别时使用默认单位
* @param suffix 后缀
* @param defaultUnit 默认单位
* @return {@link DataUnit}
*/
private static DataUnit determineDataUnit(String suffix, DataUnit defaultUnit) {
DataUnit defaultUnitToUse = (defaultUnit != null ? defaultUnit : DataUnit.BYTES);
return (StrUtil.isNotEmpty(suffix) ? DataUnit.fromSuffix(suffix) : defaultUnitToUse);
}
/**
* 是否为负数不包括0
*
* @return 负数返回true否则false
*/
public boolean isNegative() {
return this.bytes < 0;
}
/**
* 返回bytes大小
*
* @return bytes大小
*/
public long toBytes() {
return this.bytes;
}
/**
* 返回KB大小
*
* @return KB大小
*/
public long toKilobytes() {
return this.bytes / BYTES_PER_KB;
}
/**
* 返回MB大小
*
* @return MB大小
*/
public long toMegabytes() {
return this.bytes / BYTES_PER_MB;
}
/**
* 返回GB大小
*
* @return GB大小
*
*/
public long toGigabytes() {
return this.bytes / BYTES_PER_GB;
}
/**
* 返回TB大小
*
* @return TB大小
*/
public long toTerabytes() {
return this.bytes / BYTES_PER_TB;
}
@Override
public int compareTo(DataSize other) {
return Long.compare(this.bytes, other.bytes);
}
@Override
public String toString() {
return String.format("%dB", this.bytes);
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (other == null || getClass() != other.getClass()) {
return false;
}
DataSize otherSize = (DataSize) other;
return (this.bytes == otherSize.bytes);
}
@Override
public int hashCode() {
return Long.hashCode(this.bytes);
}
}

View File

@ -0,0 +1,38 @@
package cn.hutool.core.io.unit;
import java.text.DecimalFormat;
/**
* 数据大小工具类
*
* @author looly
* @since 5.3.10
*/
public class DataSizeUtil {
/**
* 解析数据大小字符串转换为bytes大小
*
* @param text 数据大小字符串类似于12KB, 5MB等
* @return bytes大小
*/
public long parse(String text) {
return DataSize.parse(text).toBytes();
}
/**
* 可读的文件大小<br>
* 参考 http://stackoverflow.com/questions/3263892/format-file-size-as-mb-gb-etc
*
* @param size Long类型大小
* @return 大小
*/
public static String format(long size) {
if (size <= 0) {
return "0";
}
int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
return new DecimalFormat("#,##0.##")
.format(size / Math.pow(1024, digitGroups)) + " " + DataUnit.UNIT_NAMES[digitGroups];
}
}

View File

@ -0,0 +1,79 @@
package cn.hutool.core.io.unit;
/**
* 数据单位封装<p>
* 此类来自于Spring-framework
*
* <p>
* <table border="1">
* <tr><th>名称</th><th>数据大小</th><th>Power&nbsp;of&nbsp;2</th><th>bytes表示</th></tr>
* <tr><td>{@link #BYTES}</td><td>1B</td><td>2^0</td><td>1</td></tr>
* <tr><td>{@link #KILOBYTES}</td><td>1KB</td><td>2^10</td><td>1,024</td></tr>
* <tr><td>{@link #MEGABYTES}</td><td>1MB</td><td>2^20</td><td>1,048,576</td></tr>
* <tr><td>{@link #GIGABYTES}</td><td>1GB</td><td>2^30</td><td>1,073,741,824</td></tr>
* <tr><td>{@link #TERABYTES}</td><td>1TB</td><td>2^40</td><td>1,099,511,627,776</td></tr>
* </table>
*
* @author Sam BrannenStephane Nicoll
* @since 5.3.10
*/
public enum DataUnit {
/**
* Bytes, 后缀表示为 {@code B}.
*/
BYTES("B", DataSize.ofBytes(1)),
/**
* Kilobytes, 后缀表示为 {@code KB}.
*/
KILOBYTES("KB", DataSize.ofKilobytes(1)),
/**
* Megabytes, 后缀表示为 {@code MB}.
*/
MEGABYTES("MB", DataSize.ofMegabytes(1)),
/**
* Gigabytes, 后缀表示为 {@code GB}.
*/
GIGABYTES("GB", DataSize.ofGigabytes(1)),
/**
* Terabytes, 后缀表示为 {@code TB}.
*/
TERABYTES("TB", DataSize.ofTerabytes(1));
public static final String[] UNIT_NAMES = new String[]{"B", "kB", "MB", "GB", "TB", "EB"};
private final String suffix;
private final DataSize size;
DataUnit(String suffix, DataSize size) {
this.suffix = suffix;
this.size = size;
}
DataSize size() {
return this.size;
}
/**
* 通过后缀返回对应的 {@link DataUnit}
*
* @param suffix 单位后缀
* @return 匹配到的{@link DataUnit}
* @throws IllegalArgumentException 后缀无法识别报错
*/
public static DataUnit fromSuffix(String suffix) {
for (DataUnit candidate : values()) {
if (candidate.suffix.equalsIgnoreCase(suffix)) {
return candidate;
}
}
throw new IllegalArgumentException("Unknown data unit suffix '" + suffix + "'");
}
}

View File

@ -0,0 +1,7 @@
/**
* 数据单位相关封装包括DataUnit数据单位和DataSize数据大小
*
* @author looly
* @since 5.3.10
*/
package cn.hutool.core.io.unit;