mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
fix code
This commit is contained in:
parent
d5e8c53b2b
commit
9261511574
@ -31,7 +31,11 @@ public class HexUtil {
|
|||||||
* @return 是否为16进制
|
* @return 是否为16进制
|
||||||
*/
|
*/
|
||||||
public static boolean isHexNumber(final String value) {
|
public static boolean isHexNumber(final String value) {
|
||||||
int index = (value.startsWith("-") ? 1 : 0);
|
if(StrUtil.startWith(value, '-')){
|
||||||
|
// issue#2875
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int index = 0;
|
||||||
if (value.startsWith("0x", index) || value.startsWith("0X", index)) {
|
if (value.startsWith("0x", index) || value.startsWith("0X", index)) {
|
||||||
index += 2;
|
index += 2;
|
||||||
} else if (value.startsWith("#", index)) {
|
} else if (value.startsWith("#", index)) {
|
||||||
|
1238
hutool-core/src/main/java/cn/hutool/core/io/FileMagicNumber.java
Executable file
1238
hutool-core/src/main/java/cn/hutool/core/io/FileMagicNumber.java
Executable file
File diff suppressed because it is too large
Load Diff
@ -5,6 +5,7 @@ import cn.hutool.core.text.StrUtil;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
@ -17,96 +18,11 @@ import java.util.concurrent.ConcurrentSkipListMap;
|
|||||||
*
|
*
|
||||||
* <p>需要注意的是,xlsx、docx等Office2007格式,全部识别为zip,因为新版采用了OpenXML格式,这些格式本质上是XML文件打包为zip</p>
|
* <p>需要注意的是,xlsx、docx等Office2007格式,全部识别为zip,因为新版采用了OpenXML格式,这些格式本质上是XML文件打包为zip</p>
|
||||||
*
|
*
|
||||||
* TODO 参考:https://github.com/sindresorhus/file-type/blob/main/core.js 重构此工具
|
|
||||||
*
|
|
||||||
* @author Looly
|
* @author Looly
|
||||||
*/
|
*/
|
||||||
public class FileTypeUtil {
|
public class FileTypeUtil {
|
||||||
|
|
||||||
private static final Map<String, String> FILE_TYPE_MAP;
|
private static final Map<String, String> FILE_TYPE_MAP = new ConcurrentSkipListMap<>();
|
||||||
|
|
||||||
static {
|
|
||||||
FILE_TYPE_MAP = new ConcurrentSkipListMap<>((s1, s2) -> {
|
|
||||||
final int len1 = s1.length();
|
|
||||||
final int len2 = s2.length();
|
|
||||||
if (len1 == len2) {
|
|
||||||
return s1.compareTo(s2);
|
|
||||||
} else {
|
|
||||||
return len2 - len1;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 2-byte signatures
|
|
||||||
// https://github.com/sindresorhus/file-type/blob/main/core.js#L90
|
|
||||||
FILE_TYPE_MAP.put("424D", "bmp"); // 位图(bmp)
|
|
||||||
FILE_TYPE_MAP.put("0B77", "ac3");
|
|
||||||
FILE_TYPE_MAP.put("7801", "dmg");
|
|
||||||
FILE_TYPE_MAP.put("4D5A", "exe");
|
|
||||||
FILE_TYPE_MAP.put("1FA0", "Z");
|
|
||||||
FILE_TYPE_MAP.put("1F9D", "Z");
|
|
||||||
|
|
||||||
// 3-byte signatures
|
|
||||||
// https://github.com/sindresorhus/file-type/blob/main/core.js#L149
|
|
||||||
FILE_TYPE_MAP.put("474946", "gif"); // GIF (gif)
|
|
||||||
FILE_TYPE_MAP.put("FFd8FF", "jpg"); // JPEG (jpg)
|
|
||||||
FILE_TYPE_MAP.put("4949BC", "jxr"); // jxr
|
|
||||||
FILE_TYPE_MAP.put("1F8B08", "gz"); // gzip
|
|
||||||
FILE_TYPE_MAP.put("425A68", "bz2"); // bz2
|
|
||||||
|
|
||||||
// check string
|
|
||||||
FILE_TYPE_MAP.put(HexUtil.encodeHexStr("MP+"), "mpc");
|
|
||||||
FILE_TYPE_MAP.put(HexUtil.encodeHexStr("FLIF"), "flif");
|
|
||||||
FILE_TYPE_MAP.put(HexUtil.encodeHexStr("8BPS"), "psd");// Photoshop (psd)
|
|
||||||
FILE_TYPE_MAP.put(HexUtil.encodeHexStr("MPCK"), "mpc");
|
|
||||||
FILE_TYPE_MAP.put(HexUtil.encodeHexStr("FORM"), "aif");// Musepack, SV8
|
|
||||||
FILE_TYPE_MAP.put(HexUtil.encodeHexStr("icns"), "icns");
|
|
||||||
|
|
||||||
FILE_TYPE_MAP.put("89504e47", "png"); // PNG (png)
|
|
||||||
FILE_TYPE_MAP.put("49492a00227105008037", "tif"); // TIFF (tif)
|
|
||||||
FILE_TYPE_MAP.put("41433130313500000000", "dwg"); // CAD (dwg)
|
|
||||||
FILE_TYPE_MAP.put("7b5c727466315c616e73", "rtf"); // Rich Text Format (rtf)
|
|
||||||
FILE_TYPE_MAP.put("46726f6d3a203d3f6762", "eml"); // Email [Outlook Express 6] (eml)
|
|
||||||
FILE_TYPE_MAP.put("5374616E64617264204A", "mdb"); // MS Access (mdb)
|
|
||||||
FILE_TYPE_MAP.put("252150532D41646F6265", "ps");
|
|
||||||
FILE_TYPE_MAP.put("255044462d312e", "pdf"); // Adobe Acrobat (pdf)
|
|
||||||
FILE_TYPE_MAP.put("2e524d46000000120001", "rmvb"); // rmvb/rm相同
|
|
||||||
FILE_TYPE_MAP.put("464c5601050000000900", "flv"); // flv与f4v相同
|
|
||||||
FILE_TYPE_MAP.put("0000001C66747970", "mp4");
|
|
||||||
FILE_TYPE_MAP.put("00000020667479706", "mp4");
|
|
||||||
FILE_TYPE_MAP.put("00000018667479706D70", "mp4");
|
|
||||||
FILE_TYPE_MAP.put("49443303000000002176", "mp3");
|
|
||||||
FILE_TYPE_MAP.put("000001ba210001000180", "mpg"); //
|
|
||||||
FILE_TYPE_MAP.put("3026b2758e66cf11a6d9", "wmv"); // wmv与asf相同
|
|
||||||
FILE_TYPE_MAP.put("52494646e27807005741", "wav"); // Wave (wav)
|
|
||||||
FILE_TYPE_MAP.put("52494646d07d60074156", "avi");
|
|
||||||
FILE_TYPE_MAP.put("4d546864000000060001", "mid"); // MIDI (mid)
|
|
||||||
FILE_TYPE_MAP.put("526172211a0700cf9073", "rar"); // WinRAR
|
|
||||||
FILE_TYPE_MAP.put("235468697320636f6e66", "ini");
|
|
||||||
FILE_TYPE_MAP.put("504B03040a0000000000", "jar");
|
|
||||||
FILE_TYPE_MAP.put("504B0304140008000800", "jar");
|
|
||||||
// MS Excel 注意:word、msi 和 excel的文件头一样
|
|
||||||
FILE_TYPE_MAP.put("d0cf11e0a1b11ae10", "xls");
|
|
||||||
FILE_TYPE_MAP.put("504B0304", "zip");
|
|
||||||
FILE_TYPE_MAP.put("4d5a9000030000000400", "exe"); // 可执行文件
|
|
||||||
FILE_TYPE_MAP.put("3c25402070616765206c", "jsp"); // jsp文件
|
|
||||||
FILE_TYPE_MAP.put("4d616e69666573742d56", "mf"); // MF文件
|
|
||||||
FILE_TYPE_MAP.put("7061636b616765207765", "java"); // java文件
|
|
||||||
FILE_TYPE_MAP.put("406563686f206f66660d", "bat"); // bat文件
|
|
||||||
FILE_TYPE_MAP.put("1f8b0800000000000000", "gz"); // gz文件
|
|
||||||
FILE_TYPE_MAP.put("cafebabe0000002e0041", "class"); // class文件
|
|
||||||
FILE_TYPE_MAP.put("49545346030000006000", "chm"); // chm文件
|
|
||||||
FILE_TYPE_MAP.put("04000000010000001300", "mxp"); // mxp文件
|
|
||||||
FILE_TYPE_MAP.put("6431303a637265617465", "torrent");
|
|
||||||
FILE_TYPE_MAP.put("6D6F6F76", "mov"); // Quicktime (mov)
|
|
||||||
FILE_TYPE_MAP.put("FF575043", "wpd"); // WordPerfect (wpd)
|
|
||||||
FILE_TYPE_MAP.put("CFAD12FEC5FD746F", "dbx"); // Outlook Express (dbx)
|
|
||||||
FILE_TYPE_MAP.put("2142444E", "pst"); // Outlook (pst)
|
|
||||||
FILE_TYPE_MAP.put("AC9EBD8F", "qdf"); // Quicken (qdf)
|
|
||||||
FILE_TYPE_MAP.put("E3828596", "pwl"); // Windows Password (pwl)
|
|
||||||
FILE_TYPE_MAP.put("2E7261FD", "ram"); // Real Audio (ram)
|
|
||||||
// https://stackoverflow.com/questions/45321665/magic-number-for-google-image-format
|
|
||||||
FILE_TYPE_MAP.put("52494646", "webp");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 增加文件类型映射<br>
|
* 增加文件类型映射<br>
|
||||||
@ -116,7 +32,7 @@ public class FileTypeUtil {
|
|||||||
* @param extName 文件扩展名
|
* @param extName 文件扩展名
|
||||||
* @return 之前已经存在的文件扩展名
|
* @return 之前已经存在的文件扩展名
|
||||||
*/
|
*/
|
||||||
public static String putFileType(final String fileStreamHexHead, final String extName) {
|
public static String putFileType(String fileStreamHexHead, String extName) {
|
||||||
return FILE_TYPE_MAP.put(fileStreamHexHead, extName);
|
return FILE_TYPE_MAP.put(fileStreamHexHead, extName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,7 +42,7 @@ public class FileTypeUtil {
|
|||||||
* @param fileStreamHexHead 文件流头部Hex信息
|
* @param fileStreamHexHead 文件流头部Hex信息
|
||||||
* @return 移除的文件扩展名
|
* @return 移除的文件扩展名
|
||||||
*/
|
*/
|
||||||
public static String removeFileType(final String fileStreamHexHead) {
|
public static String removeFileType(String fileStreamHexHead) {
|
||||||
return FILE_TYPE_MAP.remove(fileStreamHexHead);
|
return FILE_TYPE_MAP.remove(fileStreamHexHead);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,32 +52,57 @@ public class FileTypeUtil {
|
|||||||
* @param fileStreamHexHead 文件流头部16进制字符串
|
* @param fileStreamHexHead 文件流头部16进制字符串
|
||||||
* @return 文件类型,未找到为{@code null}
|
* @return 文件类型,未找到为{@code null}
|
||||||
*/
|
*/
|
||||||
public static String getType(final String fileStreamHexHead) {
|
public static String getType(String fileStreamHexHead) {
|
||||||
for (final Entry<String, String> fileTypeEntry : FILE_TYPE_MAP.entrySet()) {
|
for (Entry<String, String> fileTypeEntry : FILE_TYPE_MAP.entrySet()) {
|
||||||
if (StrUtil.startWithIgnoreCase(fileStreamHexHead, fileTypeEntry.getKey())) {
|
if (StrUtil.startWithIgnoreCase(fileStreamHexHead, fileTypeEntry.getKey())) {
|
||||||
return fileTypeEntry.getValue();
|
return fileTypeEntry.getValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
byte[] bytes = (HexUtil.decodeHex(fileStreamHexHead));
|
||||||
|
return FileMagicNumber.getMagicNumber(bytes).getExtension();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据文件流的头部信息获得文件类型
|
||||||
|
*
|
||||||
|
* @param in 文件流
|
||||||
|
* @param fileHeadSize 自定义读取文件头部的大小
|
||||||
|
* @return 文件类型,未找到为{@code null}
|
||||||
|
*/
|
||||||
|
public static String getType(InputStream in,int fileHeadSize) throws IORuntimeException {
|
||||||
|
return getType((IoUtil.readHex(in, fileHeadSize,false)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据文件流的头部信息获得文件类型<br>
|
* 根据文件流的头部信息获得文件类型<br>
|
||||||
* 注意此方法会读取头部28个bytes,造成此流接下来读取时缺少部分bytes<br>
|
* 注意此方法会读取头部一些bytes,造成此流接下来读取时缺少部分bytes<br>
|
||||||
|
* 因此如果想服用此流,流需支持{@link InputStream#reset()}方法。
|
||||||
|
* @param in {@link InputStream}
|
||||||
|
* @param isExact 是否精确匹配,如果为false,使用前64个bytes匹配,如果为true,使用前8192bytes匹配
|
||||||
|
* @return 类型,文件的扩展名,未找到为{@code null}
|
||||||
|
* @throws IORuntimeException 读取流引起的异常
|
||||||
|
*/
|
||||||
|
public static String getType(InputStream in,boolean isExact) throws IORuntimeException {
|
||||||
|
return isExact
|
||||||
|
?getType(readHex8192Upper(in))
|
||||||
|
:getType(readHex64Upper(in));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据文件流的头部信息获得文件类型<br>
|
||||||
|
* 注意此方法会读取头部64个bytes,造成此流接下来读取时缺少部分bytes<br>
|
||||||
* 因此如果想服用此流,流需支持{@link InputStream#reset()}方法。
|
* 因此如果想服用此流,流需支持{@link InputStream#reset()}方法。
|
||||||
*
|
|
||||||
* @param in {@link InputStream}
|
* @param in {@link InputStream}
|
||||||
* @return 类型,文件的扩展名,未找到为{@code null}
|
* @return 类型,文件的扩展名,未找到为{@code null}
|
||||||
* @throws IORuntimeException 读取流引起的异常
|
* @throws IORuntimeException 读取流引起的异常
|
||||||
*/
|
*/
|
||||||
public static String getType(final InputStream in) throws IORuntimeException {
|
public static String getType(InputStream in) throws IORuntimeException {
|
||||||
return getType(readHex28Upper(in));
|
return getType(in,false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据文件流的头部信息获得文件类型
|
* 根据文件流的头部信息获得文件类型
|
||||||
* 注意此方法会读取头部28个bytes,造成此流接下来读取时缺少部分bytes<br>
|
* 注意此方法会读取头部64个bytes,造成此流接下来读取时缺少部分bytes<br>
|
||||||
* 因此如果想服用此流,流需支持{@link InputStream#reset()}方法。
|
* 因此如果想服用此流,流需支持{@link InputStream#reset()}方法。
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
@ -175,22 +116,31 @@ public class FileTypeUtil {
|
|||||||
* @return 类型,文件的扩展名,未找到为{@code null}
|
* @return 类型,文件的扩展名,未找到为{@code null}
|
||||||
* @throws IORuntimeException 读取流引起的异常
|
* @throws IORuntimeException 读取流引起的异常
|
||||||
*/
|
*/
|
||||||
public static String getType(final InputStream in, final String filename) {
|
public static String getType(InputStream in, String filename) throws IORuntimeException {
|
||||||
String typeName = getType(in);
|
return getType(in,filename,false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据文件流的头部信息获得文件类型
|
||||||
|
* 注意此方法会读取头部一些bytes,造成此流接下来读取时缺少部分bytes<br>
|
||||||
|
* 因此如果想服用此流,流需支持{@link InputStream#reset()}方法。
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* 1、无法识别类型默认按照扩展名识别
|
||||||
|
* 2、xls、doc、msi头信息无法区分,按照扩展名区分
|
||||||
|
* 3、zip可能为docx、xlsx、pptx、jar、war、ofd头信息无法区分,按照扩展名区分
|
||||||
|
* </pre>
|
||||||
|
* @param in {@link InputStream}
|
||||||
|
* @param filename 文件名
|
||||||
|
* @param isExact 是否精确匹配,如果为false,使用前64个bytes匹配,如果为true,使用前8192bytes匹配
|
||||||
|
* @return 类型,文件的扩展名,未找到为{@code null}
|
||||||
|
* @throws IORuntimeException 读取流引起的异常
|
||||||
|
*/
|
||||||
|
public static String getType(InputStream in, String filename,boolean isExact) throws IORuntimeException {
|
||||||
|
String typeName = getType(in,isExact);
|
||||||
if (null == typeName) {
|
if (null == typeName) {
|
||||||
// 未成功识别类型,扩展名辅助识别
|
// 未成功识别类型,扩展名辅助识别
|
||||||
typeName = FileUtil.extName(filename);
|
typeName = FileUtil.extName(filename);
|
||||||
} else if ("xls".equals(typeName)) {
|
|
||||||
// xls、doc、msi的头一样,使用扩展名辅助判断
|
|
||||||
final String extName = FileUtil.extName(filename);
|
|
||||||
if ("doc".equalsIgnoreCase(extName)) {
|
|
||||||
typeName = "doc";
|
|
||||||
} else if ("msi".equalsIgnoreCase(extName)) {
|
|
||||||
typeName = "msi";
|
|
||||||
} else if ("ppt".equalsIgnoreCase(extName)) {
|
|
||||||
typeName = "ppt";
|
|
||||||
}
|
|
||||||
} else if ("zip".equals(typeName)) {
|
} else if ("zip".equals(typeName)) {
|
||||||
// zip可能为docx、xlsx、pptx、jar、war、ofd等格式,扩展名辅助判断
|
// zip可能为docx、xlsx、pptx、jar、war、ofd等格式,扩展名辅助判断
|
||||||
final String extName = FileUtil.extName(filename);
|
final String extName = FileUtil.extName(filename);
|
||||||
@ -235,21 +185,51 @@ public class FileTypeUtil {
|
|||||||
* <pre>
|
* <pre>
|
||||||
* 1、无法识别类型默认按照扩展名识别
|
* 1、无法识别类型默认按照扩展名识别
|
||||||
* 2、xls、doc、msi头信息无法区分,按照扩展名区分
|
* 2、xls、doc、msi头信息无法区分,按照扩展名区分
|
||||||
* 3、zip可能为docx、xlsx、pptx、jar、war头信息无法区分,按照扩展名区分
|
* 3、zip可能为jar、war头信息无法区分,按照扩展名区分
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param file 文件 {@link File}
|
||||||
|
* @param isExact 是否精确匹配,如果为false,使用前64个bytes匹配,如果为true,使用前8192bytes匹配
|
||||||
|
* @return 类型,文件的扩展名,未找到为{@code null}
|
||||||
|
* @throws IORuntimeException 读取文件引起的异常
|
||||||
|
*/
|
||||||
|
public static String getType(File file,boolean isExact) throws IORuntimeException {
|
||||||
|
FileInputStream in = null;
|
||||||
|
try {
|
||||||
|
in = IoUtil.toStream(file);
|
||||||
|
return getType(in, file.getName(),isExact);
|
||||||
|
} finally {
|
||||||
|
IoUtil.close(in);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据文件流的头部信息获得文件类型
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* 1、无法识别类型默认按照扩展名识别
|
||||||
|
* 2、xls、doc、msi头信息无法区分,按照扩展名区分
|
||||||
|
* 3、zip可能为jar、war头信息无法区分,按照扩展名区分
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* @param file 文件 {@link File}
|
* @param file 文件 {@link File}
|
||||||
* @return 类型,文件的扩展名,未找到为{@code null}
|
* @return 类型,文件的扩展名,未找到为{@code null}
|
||||||
* @throws IORuntimeException 读取文件引起的异常
|
* @throws IORuntimeException 读取文件引起的异常
|
||||||
*/
|
*/
|
||||||
public static String getType(final File file) throws IORuntimeException {
|
public static String getType(File file) throws IORuntimeException {
|
||||||
FileInputStream in = null;
|
return getType(file,false);
|
||||||
try {
|
|
||||||
in = IoUtil.toStream(file);
|
|
||||||
return getType(in, file.getName());
|
|
||||||
} finally {
|
|
||||||
IoUtil.close(in);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过路径获得文件类型
|
||||||
|
*
|
||||||
|
* @param path 路径,绝对路径或相对ClassPath的路径
|
||||||
|
* @param isExact 是否精确匹配,如果为false,使用前64个bytes匹配,如果为true,使用前8192bytes匹配
|
||||||
|
* @return 类型
|
||||||
|
* @throws IORuntimeException 读取文件引起的异常
|
||||||
|
*/
|
||||||
|
public static String getTypeByPath(String path,boolean isExact) throws IORuntimeException {
|
||||||
|
return getType(FileUtil.file(path),isExact);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -259,29 +239,34 @@ public class FileTypeUtil {
|
|||||||
* @return 类型
|
* @return 类型
|
||||||
* @throws IORuntimeException 读取文件引起的异常
|
* @throws IORuntimeException 读取文件引起的异常
|
||||||
*/
|
*/
|
||||||
public static String getTypeByPath(final String path) throws IORuntimeException {
|
public static String getTypeByPath(String path) throws IORuntimeException {
|
||||||
return getType(FileUtil.file(path));
|
return getTypeByPath(path,false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从流中读取前28个byte并转换为16进制,字母部分使用大写
|
* 从流中读取前8192个byte并转换为16进制,字母部分使用大写
|
||||||
*
|
*
|
||||||
* @param in {@link InputStream}
|
* @param in {@link InputStream}
|
||||||
* @return 16进制字符串
|
* @return 16进制字符串
|
||||||
* @throws IORuntimeException IO异常
|
* @throws IORuntimeException IO异常
|
||||||
*/
|
*/
|
||||||
public static String readHex28Upper(final InputStream in) throws IORuntimeException {
|
private static String readHex8192Upper(final InputStream in) throws IORuntimeException {
|
||||||
return IoUtil.readHex(in, 28, false);
|
try {
|
||||||
|
final int i = in.available();
|
||||||
|
return IoUtil.readHex(in, Math.min(8192, in.available()), false);
|
||||||
|
} catch (final IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从流中读取前28个byte并转换为16进制,字母部分使用小写
|
* 从流中读取前64个byte并转换为16进制,字母部分使用大写
|
||||||
*
|
*
|
||||||
* @param in {@link InputStream}
|
* @param in {@link InputStream}
|
||||||
* @return 16进制字符串
|
* @return 16进制字符串
|
||||||
* @throws IORuntimeException IO异常
|
* @throws IORuntimeException IO异常
|
||||||
*/
|
*/
|
||||||
public static String readHex28Lower(final InputStream in) throws IORuntimeException {
|
private static String readHex64Upper(InputStream in) throws IORuntimeException {
|
||||||
return IoUtil.readHex(in, 28, true);
|
return IoUtil.readHex(in, 64, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -510,6 +510,12 @@ public class PathUtil {
|
|||||||
public static Path moveContent(final Path src, final Path target, final boolean isOverride) {
|
public static Path moveContent(final Path src, final Path target, final boolean isOverride) {
|
||||||
Assert.notNull(src, "Src path must be not null !");
|
Assert.notNull(src, "Src path must be not null !");
|
||||||
Assert.notNull(target, "Target path must be not null !");
|
Assert.notNull(target, "Target path must be not null !");
|
||||||
|
|
||||||
|
if(equals(src, target)){
|
||||||
|
// issue#2845,当用户传入目标路径与源路径一致时,直接返回,否则会导致删除风险。
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
final CopyOption[] options = isOverride ? new CopyOption[]{StandardCopyOption.REPLACE_EXISTING} : new CopyOption[]{};
|
final CopyOption[] options = isOverride ? new CopyOption[]{StandardCopyOption.REPLACE_EXISTING} : new CopyOption[]{};
|
||||||
|
|
||||||
// 自动创建目标的父目录
|
// 自动创建目标的父目录
|
||||||
|
@ -294,7 +294,7 @@ public class FieldUtil {
|
|||||||
try {
|
try {
|
||||||
field.set(obj instanceof Class ? null : obj, value);
|
field.set(obj instanceof Class ? null : obj, value);
|
||||||
} catch (final IllegalAccessException e) {
|
} catch (final IllegalAccessException e) {
|
||||||
throw new UtilException(e, "IllegalAccess for {}.{}", obj, field.getName());
|
throw new UtilException(e, "IllegalAccess for [{}.{}]", null == obj ? field.getDeclaringClass() : obj, field.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,6 +249,7 @@ public class ModifierUtil {
|
|||||||
if (null == field || false == hasModifier(field, ModifierUtil.ModifierType.FINAL)) {
|
if (null == field || false == hasModifier(field, ModifierUtil.ModifierType.FINAL)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//将字段的访问权限设为true:即去除private修饰符的影响
|
//将字段的访问权限设为true:即去除private修饰符的影响
|
||||||
if (false == field.isAccessible()) {
|
if (false == field.isAccessible()) {
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
@ -263,7 +264,7 @@ public class ModifierUtil {
|
|||||||
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
|
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
|
||||||
} catch (final NoSuchFieldException | IllegalAccessException e) {
|
} catch (final NoSuchFieldException | IllegalAccessException e) {
|
||||||
//内部,工具类,基本不抛出异常
|
//内部,工具类,基本不抛出异常
|
||||||
throw new UtilException(e, "IllegalAccess for {}.{}", field.getDeclaringClass(), field.getName());
|
throw new UtilException(e, "IllegalAccess for [{}.{}]", field.getDeclaringClass(), field.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//-------------------------------------------------------------------------------------------------------- Private method start
|
//-------------------------------------------------------------------------------------------------------- Private method start
|
||||||
|
@ -133,6 +133,34 @@ public class CoordinateUtil {
|
|||||||
return gcj02ToWgs84(gcj02.lng, gcj02.lat);
|
return gcj02ToWgs84(gcj02.lng, gcj02.lat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WGS84 坐标转为 墨卡托投影
|
||||||
|
*
|
||||||
|
* @param lng 经度值
|
||||||
|
* @param lat 纬度值
|
||||||
|
* @return 墨卡托投影
|
||||||
|
*/
|
||||||
|
public static Coordinate wgs84ToMercator(final double lng, final double lat) {
|
||||||
|
final double x = lng * 20037508.342789244 / 180;
|
||||||
|
double y = Math.log(Math.tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180);
|
||||||
|
y = y * 20037508.342789244 / 180;
|
||||||
|
return new Coordinate(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 墨卡托投影 转为 WGS84 坐标
|
||||||
|
*
|
||||||
|
* @param mercatorX 墨卡托X坐标
|
||||||
|
* @param mercatorY 墨卡托Y坐标
|
||||||
|
* @return WGS84 坐标
|
||||||
|
*/
|
||||||
|
public static Coordinate mercatorToWgs84(final double mercatorX, final double mercatorY) {
|
||||||
|
final double x = mercatorX / 20037508.342789244 * 180;
|
||||||
|
double y = mercatorY / 20037508.342789244 * 180;
|
||||||
|
y = 180 / Math.PI * (2 * Math.atan(Math.exp(y * Math.PI / 180)) - Math.PI / 2);
|
||||||
|
return new Coordinate(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------- Private methods begin
|
//----------------------------------------------------------------------------------- Private methods begin
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -41,7 +41,6 @@ import javax.xml.xpath.XPath;
|
|||||||
import javax.xml.xpath.XPathConstants;
|
import javax.xml.xpath.XPathConstants;
|
||||||
import javax.xml.xpath.XPathExpressionException;
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
import javax.xml.xpath.XPathFactory;
|
import javax.xml.xpath.XPathFactory;
|
||||||
import java.beans.XMLDecoder;
|
|
||||||
import java.beans.XMLEncoder;
|
import java.beans.XMLEncoder;
|
||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
import java.io.BufferedWriter;
|
import java.io.BufferedWriter;
|
||||||
@ -333,51 +332,6 @@ public class XmlUtil {
|
|||||||
xmlStr = cleanInvalid(xmlStr);
|
xmlStr = cleanInvalid(xmlStr);
|
||||||
return readXML(StrUtil.getReader(xmlStr));
|
return readXML(StrUtil.getReader(xmlStr));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 从XML中读取对象 Reads serialized object from the XML file.
|
|
||||||
*
|
|
||||||
* @param <T> 对象类型
|
|
||||||
* @param source XML文件
|
|
||||||
* @return 对象
|
|
||||||
*/
|
|
||||||
public static <T> T readObjectFromXml(final File source) {
|
|
||||||
return readObjectFromXml(new InputSource(FileUtil.getInputStream(source)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从XML中读取对象 Reads serialized object from the XML file.
|
|
||||||
*
|
|
||||||
* @param <T> 对象类型
|
|
||||||
* @param xmlStr XML内容
|
|
||||||
* @return 对象
|
|
||||||
* @since 3.2.0
|
|
||||||
*/
|
|
||||||
public static <T> T readObjectFromXml(final String xmlStr) {
|
|
||||||
return readObjectFromXml(new InputSource(StrUtil.getReader(xmlStr)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从XML中读取对象 Reads serialized object from the XML file.
|
|
||||||
*
|
|
||||||
* @param <T> 对象类型
|
|
||||||
* @param source {@link InputSource}
|
|
||||||
* @return 对象
|
|
||||||
* @since 3.2.0
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static <T> T readObjectFromXml(final InputSource source) {
|
|
||||||
Object result;
|
|
||||||
XMLDecoder xmldec = null;
|
|
||||||
try {
|
|
||||||
xmldec = new XMLDecoder(source);
|
|
||||||
result = xmldec.readObject();
|
|
||||||
} finally {
|
|
||||||
IoUtil.close(xmldec);
|
|
||||||
}
|
|
||||||
return (T) result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------- Write
|
// -------------------------------------------------------------------------------------- Write
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -56,18 +56,6 @@ public class FileTypeUtilTest {
|
|||||||
Console.log(type);
|
Console.log(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
@Ignore
|
|
||||||
public void ofdTest() {
|
|
||||||
final File file = FileUtil.file("e:/test.ofd");
|
|
||||||
final String hex = FileTypeUtil.readHex28Upper(FileUtil.getInputStream(file));
|
|
||||||
Console.log(hex);
|
|
||||||
final String type = FileTypeUtil.getType(file);
|
|
||||||
Console.log(type);
|
|
||||||
Assert.assertEquals("ofd", type);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore
|
@Ignore
|
||||||
public void inputStreamAndFilenameTest() {
|
public void inputStreamAndFilenameTest() {
|
||||||
@ -97,16 +85,4 @@ public class FileTypeUtilTest {
|
|||||||
final String type = FileTypeUtil.getType(inputStream);
|
final String type = FileTypeUtil.getType(inputStream);
|
||||||
Console.log(type);
|
Console.log(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void readHex28LowerTest() {
|
|
||||||
final String s = FileTypeUtil.readHex28Lower(ResourceUtil.getStream("hutool.jpg"));
|
|
||||||
Assert.assertEquals("ffd8ffe000104a46494600010101006000600000ffe1095845786966", s);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void readHex28UpperTest() {
|
|
||||||
final String s = FileTypeUtil.readHex28Upper(ResourceUtil.getStream("hutool.jpg"));
|
|
||||||
Assert.assertEquals("FFD8FFE000104A46494600010101006000600000FFE1095845786966", s);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,10 @@ public class HexUtilTest {
|
|||||||
// 错误的
|
// 错误的
|
||||||
a = "0x0000001000T00001158e460913d00000";
|
a = "0x0000001000T00001158e460913d00000";
|
||||||
Assert.assertFalse(HexUtil.isHexNumber(a));
|
Assert.assertFalse(HexUtil.isHexNumber(a));
|
||||||
|
|
||||||
|
// 错误的,https://github.com/dromara/hutool/issues/2857
|
||||||
|
a = "-1";
|
||||||
|
Assert.assertFalse(HexUtil.isHexNumber(a));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package cn.hutool.crypto.symmetric;
|
package cn.hutool.crypto.symmetric;
|
||||||
|
|
||||||
import cn.hutool.core.text.StrUtil;
|
import cn.hutool.core.text.StrUtil;
|
||||||
|
import cn.hutool.crypto.KeyUtil;
|
||||||
import cn.hutool.crypto.Mode;
|
import cn.hutool.crypto.Mode;
|
||||||
import cn.hutool.crypto.Padding;
|
import cn.hutool.crypto.Padding;
|
||||||
import cn.hutool.crypto.SecureUtil;
|
import cn.hutool.crypto.SecureUtil;
|
||||||
@ -12,6 +13,59 @@ import org.junit.Test;
|
|||||||
*/
|
*/
|
||||||
public class DesTest {
|
public class DesTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void desTest() {
|
||||||
|
final String content = "test中文";
|
||||||
|
|
||||||
|
final byte[] key = KeyUtil.generateKey(SymmetricAlgorithm.DES.getValue()).getEncoded();
|
||||||
|
|
||||||
|
final SymmetricCrypto des = new SymmetricCrypto(SymmetricAlgorithm.DES, key);
|
||||||
|
final byte[] encrypt = des.encrypt(content);
|
||||||
|
final byte[] decrypt = des.decrypt(encrypt);
|
||||||
|
|
||||||
|
Assert.assertEquals(content, StrUtil.utf8Str(decrypt));
|
||||||
|
|
||||||
|
final String encryptHex = des.encryptHex(content);
|
||||||
|
final String decryptStr = des.decryptStr(encryptHex);
|
||||||
|
|
||||||
|
Assert.assertEquals(content, decryptStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void desTest2() {
|
||||||
|
final String content = "test中文";
|
||||||
|
|
||||||
|
final byte[] key = KeyUtil.generateKey(SymmetricAlgorithm.DES.getValue()).getEncoded();
|
||||||
|
|
||||||
|
final DES des = SecureUtil.des(key);
|
||||||
|
final byte[] encrypt = des.encrypt(content);
|
||||||
|
final byte[] decrypt = des.decrypt(encrypt);
|
||||||
|
|
||||||
|
Assert.assertEquals(content, StrUtil.utf8Str(decrypt));
|
||||||
|
|
||||||
|
final String encryptHex = des.encryptHex(content);
|
||||||
|
final String decryptStr = des.decryptStr(encryptHex);
|
||||||
|
|
||||||
|
Assert.assertEquals(content, decryptStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void desTest3() {
|
||||||
|
final String content = "test中文";
|
||||||
|
|
||||||
|
final DES des = new DES(Mode.CTS, Padding.PKCS5Padding, "0CoJUm6Qyw8W8jud".getBytes(), "01020304".getBytes());
|
||||||
|
|
||||||
|
final byte[] encrypt = des.encrypt(content);
|
||||||
|
final byte[] decrypt = des.decrypt(encrypt);
|
||||||
|
|
||||||
|
Assert.assertEquals(content, StrUtil.utf8Str(decrypt));
|
||||||
|
|
||||||
|
final String encryptHex = des.encryptHex(content);
|
||||||
|
final String decryptStr = des.decryptStr(encryptHex);
|
||||||
|
|
||||||
|
Assert.assertEquals(content, decryptStr);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void encryptDecryptTest(){
|
public void encryptDecryptTest(){
|
||||||
final String content = "我是一个测试的test字符串123";
|
final String content = "我是一个测试的test字符串123";
|
||||||
|
@ -172,59 +172,6 @@ public class SymmetricTest {
|
|||||||
Assert.assertEquals(content, decryptStr);
|
Assert.assertEquals(content, decryptStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void desTest() {
|
|
||||||
final String content = "test中文";
|
|
||||||
|
|
||||||
final byte[] key = KeyUtil.generateKey(SymmetricAlgorithm.DES.getValue()).getEncoded();
|
|
||||||
|
|
||||||
final SymmetricCrypto des = new SymmetricCrypto(SymmetricAlgorithm.DES, key);
|
|
||||||
final byte[] encrypt = des.encrypt(content);
|
|
||||||
final byte[] decrypt = des.decrypt(encrypt);
|
|
||||||
|
|
||||||
Assert.assertEquals(content, StrUtil.utf8Str(decrypt));
|
|
||||||
|
|
||||||
final String encryptHex = des.encryptHex(content);
|
|
||||||
final String decryptStr = des.decryptStr(encryptHex);
|
|
||||||
|
|
||||||
Assert.assertEquals(content, decryptStr);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void desTest2() {
|
|
||||||
final String content = "test中文";
|
|
||||||
|
|
||||||
final byte[] key = KeyUtil.generateKey(SymmetricAlgorithm.DES.getValue()).getEncoded();
|
|
||||||
|
|
||||||
final DES des = SecureUtil.des(key);
|
|
||||||
final byte[] encrypt = des.encrypt(content);
|
|
||||||
final byte[] decrypt = des.decrypt(encrypt);
|
|
||||||
|
|
||||||
Assert.assertEquals(content, StrUtil.utf8Str(decrypt));
|
|
||||||
|
|
||||||
final String encryptHex = des.encryptHex(content);
|
|
||||||
final String decryptStr = des.decryptStr(encryptHex);
|
|
||||||
|
|
||||||
Assert.assertEquals(content, decryptStr);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void desTest3() {
|
|
||||||
final String content = "test中文";
|
|
||||||
|
|
||||||
final DES des = new DES(Mode.CTS, Padding.PKCS5Padding, "0CoJUm6Qyw8W8jud".getBytes(), "01020304".getBytes());
|
|
||||||
|
|
||||||
final byte[] encrypt = des.encrypt(content);
|
|
||||||
final byte[] decrypt = des.decrypt(encrypt);
|
|
||||||
|
|
||||||
Assert.assertEquals(content, StrUtil.utf8Str(decrypt));
|
|
||||||
|
|
||||||
final String encryptHex = des.encryptHex(content);
|
|
||||||
final String decryptStr = des.decryptStr(encryptHex);
|
|
||||||
|
|
||||||
Assert.assertEquals(content, decryptStr);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void desdeTest() {
|
public void desdeTest() {
|
||||||
final String content = "test中文";
|
final String content = "test中文";
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
package cn.hutool.http.client;
|
||||||
|
|
||||||
|
import cn.hutool.http.client.engine.jdk.HttpUrlConnectionUtil;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class HttpUrlConnectionUtilTest {
|
||||||
|
@Test
|
||||||
|
public void allowPatchTest() {
|
||||||
|
HttpUrlConnectionUtil.allowPatch();
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user