mirror of
https://gitee.com/dromara/hutool.git
synced 2025-05-03 20:27:58 +08:00
fix double bug
This commit is contained in:
parent
b5297bd7e6
commit
a3b3743f3f
@ -11,12 +11,14 @@
|
||||
* 【core】 修正DateUtil.thisWeekOfMonth注释错误(issue#614@Github)
|
||||
* 【core】 DateUtil增加toLocalDate等方法,DateTime更好的支持时区
|
||||
* 【core】 BeanUtil.getProperty返回泛型对象(issue#I14PIW@Gitee)
|
||||
* 【core】 FileTypeUtil使用扩展名辅助判断类型(issue#I14JBH@Gitee)
|
||||
|
||||
### Bug修复
|
||||
* 【db】 修复MetaUtil.getTableMeta()方法未释放ResultSet的bug(issue#I148GH@Gitee)
|
||||
* 【core】 修复DateUtil.age闰年导致的问题(issue#I14BVN@Gitee)
|
||||
* 【extra】 修复ServletUtil.getCookie大小写问题(pr#79@Gitee)
|
||||
* 【core】 修复IdcardUtil.isValidCard18报错问题(issue#I14LTJ@Gitee)
|
||||
* 【poi】 修复double值可能存在的精度问题(issue#I14FG1@Gitee)
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
@ -11,13 +11,12 @@ import cn.hutool.core.util.StrUtil;
|
||||
|
||||
/**
|
||||
* 文件类型判断工具类
|
||||
*
|
||||
* <p>此工具根据文件的前几位bytes猜测文件类型,对于文本、zip判断不准确,对于视频、图片类型判断准确</p>
|
||||
*
|
||||
* <p>需要注意的是,xlsx、docx等Office2007格式,全部识别为zip,因为新版采用了OpenXML格式,这些格式本质上是XML文件打包为zip</p>
|
||||
*
|
||||
* @author Looly
|
||||
*
|
||||
* <p>此工具根据文件的前几位bytes猜测文件类型,对于文本、zip判断不准确,对于视频、图片类型判断准确</p>
|
||||
*
|
||||
* <p>需要注意的是,xlsx、docx等Office2007格式,全部识别为zip,因为新版采用了OpenXML格式,这些格式本质上是XML文件打包为zip</p>
|
||||
*
|
||||
* @author Looly
|
||||
*/
|
||||
public class FileTypeUtil {
|
||||
|
||||
@ -38,7 +37,6 @@ public class FileTypeUtil {
|
||||
fileTypeMap.put("7b5c727466315c616e73", "rtf"); // Rich Text Format (rtf)
|
||||
fileTypeMap.put("38425053000100000000", "psd"); // Photoshop (psd)
|
||||
fileTypeMap.put("46726f6d3a203d3f6762", "eml"); // Email [Outlook Express 6] (eml)
|
||||
fileTypeMap.put("d0cf11e0a1b11ae10000", "doc"); // MS Excel 注意:word、msi 和 excel的文件头一样
|
||||
fileTypeMap.put("5374616E64617264204A", "mdb"); // MS Access (mdb)
|
||||
fileTypeMap.put("252150532D41646F6265", "ps");
|
||||
fileTypeMap.put("255044462d312e", "pdf"); // Adobe Acrobat (pdf)
|
||||
@ -55,7 +53,8 @@ public class FileTypeUtil {
|
||||
fileTypeMap.put("235468697320636f6e66", "ini");
|
||||
fileTypeMap.put("504B03040a0000000000", "jar");
|
||||
fileTypeMap.put("504B0304140008000800", "jar");
|
||||
fileTypeMap.put("D0CF11E0A1B11AE10", "xls");// xls文件
|
||||
// MS Excel 注意:word、msi 和 excel的文件头一样
|
||||
fileTypeMap.put("d0cf11e0a1b11ae10", "xls");
|
||||
fileTypeMap.put("504B0304", "zip");
|
||||
fileTypeMap.put("4d5a9000030000000400", "exe");// 可执行文件
|
||||
fileTypeMap.put("3c25402070616765206c", "jsp");// jsp文件
|
||||
@ -79,9 +78,9 @@ public class FileTypeUtil {
|
||||
/**
|
||||
* 增加文件类型映射<br>
|
||||
* 如果已经存在将覆盖之前的映射
|
||||
*
|
||||
*
|
||||
* @param fileStreamHexHead 文件流头部Hex信息
|
||||
* @param extName 文件扩展名
|
||||
* @param extName 文件扩展名
|
||||
* @return 之前已经存在的文件扩展名
|
||||
*/
|
||||
public static String putFileType(String fileStreamHexHead, String extName) {
|
||||
@ -90,7 +89,7 @@ public class FileTypeUtil {
|
||||
|
||||
/**
|
||||
* 移除文件类型映射
|
||||
*
|
||||
*
|
||||
* @param fileStreamHexHead 文件流头部Hex信息
|
||||
* @return 移除的文件扩展名
|
||||
*/
|
||||
@ -100,13 +99,13 @@ public class FileTypeUtil {
|
||||
|
||||
/**
|
||||
* 根据文件流的头部信息获得文件类型
|
||||
*
|
||||
*
|
||||
* @param fileStreamHexHead 文件流头部16进制字符串
|
||||
* @return 文件类型,未找到为<code>null</code>
|
||||
*/
|
||||
public static String getType(String fileStreamHexHead) {
|
||||
for (Entry<String, String> fileTypeEntry : fileTypeMap.entrySet()) {
|
||||
if(StrUtil.startWithIgnoreCase(fileStreamHexHead, fileTypeEntry.getKey())) {
|
||||
if (StrUtil.startWithIgnoreCase(fileStreamHexHead, fileTypeEntry.getKey())) {
|
||||
return fileTypeEntry.getValue();
|
||||
}
|
||||
}
|
||||
@ -115,7 +114,7 @@ public class FileTypeUtil {
|
||||
|
||||
/**
|
||||
* 根据文件流的头部信息获得文件类型
|
||||
*
|
||||
*
|
||||
* @param in {@link InputStream}
|
||||
* @return 类型,文件的扩展名,未找到为<code>null</code>
|
||||
* @throws IORuntimeException 读取流引起的异常
|
||||
@ -126,24 +125,59 @@ public class FileTypeUtil {
|
||||
|
||||
/**
|
||||
* 根据文件流的头部信息获得文件类型
|
||||
*
|
||||
*
|
||||
* <pre>
|
||||
* 1、无法识别类型默认按照扩展名识别
|
||||
* 2、xls、doc、msi头信息无法区分,按照扩展名区分
|
||||
* 3、zip可能为docx、xlsx、pptx、jar、war头信息无法区分,按照扩展名区分
|
||||
* </pre>
|
||||
*
|
||||
* @param file 文件 {@link File}
|
||||
* @return 类型,文件的扩展名,未找到为<code>null</code>
|
||||
* @throws IORuntimeException 读取文件引起的异常
|
||||
*/
|
||||
public static String getType(File file) throws IORuntimeException {
|
||||
String typeName;
|
||||
FileInputStream in = null;
|
||||
try {
|
||||
in = IoUtil.toStream(file);
|
||||
return getType(in);
|
||||
typeName = getType(in);
|
||||
} finally {
|
||||
IoUtil.close(in);
|
||||
}
|
||||
|
||||
if (null == typeName) {
|
||||
// 未成功识别类型,扩展名辅助识别
|
||||
typeName = FileUtil.extName(file);
|
||||
} else if ("xls".equals(typeName)) {
|
||||
// xls、doc、msi的头一样,使用扩展名辅助判断
|
||||
final String extName = FileUtil.extName(file);
|
||||
if ("doc".equalsIgnoreCase(extName)) {
|
||||
typeName = "doc";
|
||||
} else if ("msi".equalsIgnoreCase(extName)) {
|
||||
typeName = "msi";
|
||||
}
|
||||
} else if ("zip".equals(typeName)) {
|
||||
// zip可能为docx、xlsx、pptx、jar、war等格式,扩展名辅助判断
|
||||
final String extName = FileUtil.extName(file);
|
||||
if ("docx".equalsIgnoreCase(extName)) {
|
||||
typeName = "docx";
|
||||
} else if ("xlsx".equalsIgnoreCase(extName)) {
|
||||
typeName = "xlsx";
|
||||
} else if ("pptx".equalsIgnoreCase(extName)) {
|
||||
typeName = "pptx";
|
||||
} else if ("jar".equalsIgnoreCase(extName)) {
|
||||
typeName = "jar";
|
||||
} else if ("war".equalsIgnoreCase(extName)) {
|
||||
typeName = "war";
|
||||
}
|
||||
}
|
||||
return typeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过路径获得文件类型
|
||||
*
|
||||
*
|
||||
* @param path 路径,绝对路径或相对ClassPath的路径
|
||||
* @return 类型
|
||||
* @throws IORuntimeException 读取文件引起的异常
|
||||
|
@ -1551,7 +1551,7 @@ public class FileUtil {
|
||||
pathToUse = StrUtil.removePrefixIgnoreCase(pathToUse, URLUtil.FILE_URL_PREFIX);
|
||||
|
||||
// 识别home目录形式,并转换为绝对路径
|
||||
if(pathToUse.startsWith("~")){
|
||||
if (pathToUse.startsWith("~")) {
|
||||
pathToUse = pathToUse.replace("~", getUserHomePath());
|
||||
}
|
||||
|
||||
@ -1875,6 +1875,12 @@ public class FileUtil {
|
||||
/**
|
||||
* 根据文件流的头部信息获得文件类型
|
||||
*
|
||||
* <pre>
|
||||
* 1、无法识别类型默认按照扩展名识别
|
||||
* 2、xls、doc、msi头信息无法区分,按照扩展名区分
|
||||
* 3、zip可能为docx、xlsx、pptx、jar、war头信息无法区分,按照扩展名区分
|
||||
* </pre>
|
||||
*
|
||||
* @param file 文件 {@link File}
|
||||
* @return 类型,文件的扩展名,未找到为<code>null</code>
|
||||
* @throws IORuntimeException IO异常
|
||||
|
@ -781,23 +781,9 @@ public class IoUtil {
|
||||
return toStream(content, CharsetUtil.CHARSET_UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* String 转为流
|
||||
*
|
||||
* @param content 内容bytes
|
||||
* @return 字节流
|
||||
* @since 4.1.8
|
||||
*/
|
||||
public static ByteArrayInputStream toStream(byte[] content) {
|
||||
if (content == null) {
|
||||
return null;
|
||||
}
|
||||
return new ByteArrayInputStream(content);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件转为流
|
||||
*
|
||||
*
|
||||
* @param file 文件
|
||||
* @return {@link FileInputStream}
|
||||
*/
|
||||
@ -809,6 +795,20 @@ public class IoUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* String 转为流
|
||||
*
|
||||
* @param content 内容bytes
|
||||
* @return 字节流
|
||||
* @since 4.1.8
|
||||
*/
|
||||
public static ByteArrayInputStream toStream(byte[] content) {
|
||||
if (content == null) {
|
||||
return null;
|
||||
}
|
||||
return new ByteArrayInputStream(content);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为{@link BufferedInputStream}
|
||||
*
|
||||
|
@ -1,14 +1,11 @@
|
||||
package cn.hutool.core.io;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import cn.hutool.core.lang.Console;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import cn.hutool.core.io.FileTypeUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.lang.Console;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* 文件类型判断单元测试
|
||||
@ -36,4 +33,12 @@ public class FileTypeUtilTest {
|
||||
String type = FileTypeUtil.getType(file);
|
||||
Console.log(type);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void docTest() {
|
||||
File file = FileUtil.file("f:/test/test.doc");
|
||||
String type = FileTypeUtil.getType(file);
|
||||
Console.log(type);
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,9 @@
|
||||
package cn.hutool.poi.excel.cell;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.poi.excel.StyleSet;
|
||||
import cn.hutool.poi.excel.editors.TrimEditor;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.CellStyle;
|
||||
import org.apache.poi.ss.usermodel.CellType;
|
||||
@ -13,13 +12,14 @@ import org.apache.poi.ss.usermodel.RichTextString;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.ss.util.NumberToTextConverter;
|
||||
import org.apache.poi.ss.util.RegionUtil;
|
||||
import org.apache.poi.ss.util.SheetUtil;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.poi.excel.StyleSet;
|
||||
import cn.hutool.poi.excel.editors.TrimEditor;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Excel表格中单元格工具类
|
||||
@ -27,6 +27,7 @@ import cn.hutool.poi.excel.editors.TrimEditor;
|
||||
* @author looly
|
||||
* @since 4.0.7
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class CellUtil {
|
||||
|
||||
/**
|
||||
@ -283,26 +284,26 @@ public class CellUtil {
|
||||
final double value = cell.getNumericCellValue();
|
||||
|
||||
final CellStyle style = cell.getCellStyle();
|
||||
if (null == style) {
|
||||
return value;
|
||||
}
|
||||
if (null != style) {
|
||||
final short formatIndex = style.getDataFormat();
|
||||
// 判断是否为日期
|
||||
if (isDateType(cell, formatIndex)) {
|
||||
return DateUtil.date(cell.getDateCellValue());// 使用Hutool的DateTime包装
|
||||
}
|
||||
|
||||
final short formatIndex = style.getDataFormat();
|
||||
// 判断是否为日期
|
||||
if (isDateType(cell, formatIndex)) {
|
||||
return DateUtil.date(cell.getDateCellValue());// 使用Hutool的DateTime包装
|
||||
}
|
||||
|
||||
final String format = style.getDataFormatString();
|
||||
// 普通数字
|
||||
if (null != format && format.indexOf(StrUtil.C_DOT) < 0) {
|
||||
final long longPart = (long) value;
|
||||
if (longPart == value) {
|
||||
// 对于无小数部分的数字类型,转为Long
|
||||
return longPart;
|
||||
final String format = style.getDataFormatString();
|
||||
// 普通数字
|
||||
if (null != format && format.indexOf(StrUtil.C_DOT) < 0) {
|
||||
final long longPart = (long) value;
|
||||
if (((double) longPart) == value) {
|
||||
// 对于无小数部分的数字类型,转为Long
|
||||
return longPart;
|
||||
}
|
||||
}
|
||||
}
|
||||
return value;
|
||||
|
||||
// 某些Excel单元格值为double计算结果,可能导致精度问题,通过转换解决精度问题。
|
||||
return Double.parseDouble(NumberToTextConverter.toText(value));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -190,4 +190,14 @@ public class ExcelReadTest {
|
||||
return "Person [name=" + name + ", gender=" + gender + ", age=" + age + "]";
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void readDoubleTest(){
|
||||
ExcelReader reader = ExcelUtil.getReader("f:/test/doubleTest.xls");
|
||||
final List<List<Object>> read = reader.read();
|
||||
for (List<Object> list : read) {
|
||||
Console.log(list.get(8));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user