Compare commits
68 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
aae9c61ab6 | |
|
|
d8f1508739 | |
|
|
3afdea9d5d | |
|
|
4826273f09 | |
|
|
fab7653cd4 | |
|
|
c42183df46 | |
|
|
efa7dff66b | |
|
|
be283842ef | |
|
|
c9d43270da | |
|
|
898ca7d268 | |
|
|
71d743d7dc | |
|
|
802c86fc84 | |
|
|
e2f302f4cf | |
|
|
3a1db020a7 | |
|
|
1cbc7da53f | |
|
|
ae9f3861c4 | |
|
|
4658a0e87d | |
|
|
1521e9e8f0 | |
|
|
ea64d8a4d6 | |
|
|
4e2496a12d | |
|
|
a6e968233c | |
|
|
535a1067ab | |
|
|
c52385f05b | |
|
|
5844e5f84e | |
|
|
e8a86c6dbe | |
|
|
ab50571bb5 | |
|
|
99e527e9b4 | |
|
|
1cfad85561 | |
|
|
58b84830cd | |
|
|
1e144e16fe | |
|
|
a891c71500 | |
|
|
0eb0833235 | |
|
|
5f0a8897df | |
|
|
fa592214b3 | |
|
|
c068790359 | |
|
|
c68bf685c1 | |
|
|
b9e76d8342 | |
|
|
d3ca6ca085 | |
|
|
2a494edaf4 | |
|
|
9a268940ae | |
|
|
0ae9d7714c | |
|
|
b648e5ebe8 | |
|
|
5ad28d92a9 | |
|
|
690560fcae | |
|
|
b44b4e2a63 | |
|
|
37ea4f5925 | |
|
|
d0ed30eeee | |
|
|
3fbc93f4b0 | |
|
|
b5f1c1fbb7 | |
|
|
08d0ad7d4b | |
|
|
0cc5615705 | |
|
|
49cc0b0495 | |
|
|
47a0bc14e3 | |
|
|
8b6bfdb2ea | |
|
|
a932a10991 | |
|
|
2d3deacaae | |
|
|
94e5507391 | |
|
|
b45510266a | |
|
|
64fd1cc74f | |
|
|
cba5e3cfb2 | |
|
|
5c20a88e1d | |
|
|
28a71f32cc | |
|
|
1ffd4864f8 | |
|
|
09b00fb5b5 | |
|
|
ac3bf71a62 | |
|
|
182982919d | |
|
|
a5d0ddc67b | |
|
|
499c7784d7 |
|
|
@ -23,7 +23,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
java: [ 8, 11, 17]
|
||||
java: [ 8, 11, 17, 21]
|
||||
distribution: [ 'adopt' ]
|
||||
fail-fast: false
|
||||
max-parallel: 4
|
||||
|
|
@ -37,7 +37,7 @@ jobs:
|
|||
java-version: ${{ matrix.java }}
|
||||
distribution: ${{ matrix.distribution }}
|
||||
- name: Cache local Maven repository
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@main
|
||||
with:
|
||||
path: ~/.m2/repository
|
||||
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
||||
|
|
@ -46,7 +46,11 @@ jobs:
|
|||
- name: Chmod
|
||||
run: chmod +x mvnw
|
||||
- name: Test with Maven
|
||||
if: ${{ matrix.java == '8' }}
|
||||
run: ./mvnw test -B -Dmaven.test.skip=false
|
||||
- name: Test with Maven
|
||||
if: ${{ matrix.java != '8' }}
|
||||
run: ./mvnw test -B -Dmaven.test.skip=false -DargLine="--add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/sun.reflect.annotation=ALL-UNNAMED"
|
||||
- name: Maven Build
|
||||
run: ./mvnw install -B -V
|
||||
- name: Java Doc
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ jobs:
|
|||
server-username: MAVEN_USERNAME
|
||||
server-password: MAVEN_PASSWORD
|
||||
- name: Cache local Maven repository
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@main
|
||||
with:
|
||||
path: ~/.m2/repository
|
||||
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
||||
|
|
|
|||
68
README.md
68
README.md
|
|
@ -1,3 +1,5 @@
|
|||
|
||||
|
||||
EasyExcel
|
||||
======================
|
||||
[](https://github.com/alibaba/easyexcel/actions/workflows/ci.yml?query=branch%3Amaster)
|
||||
|
|
@ -5,26 +7,32 @@ EasyExcel
|
|||
[](http://www.apache.org/licenses/LICENSE-2.0.html)
|
||||
[](https://opensource.alibaba.com/contribution_leaderboard/details?projectValue=easyexcel)
|
||||
|
||||
# 维护公告
|
||||
尊敬的EasyExcel用户们:
|
||||
|
||||
首先,我们想表达最深的谢意,感谢您长期以来对EasyExcel的信任与支持。在这段旅程中,EasyExcel有幸陪伴众多开发者和企业共同成长,见证了无数数据处理任务的高效完成。
|
||||
|
||||
近期,我们注意到市场上出现了更多优秀的数据处理工具和解决方案,为用户提供了更丰富的选择。为了确保每位用户都能享受到最佳的体验和服务,我们决定采取一项重要措施:EasyExcel将逐步进入维护模式,并给予用户充足的时间评估并迁移到其他产品。同时,我们也欢迎并乐于见到社区内外分享关于同类优秀产品的使用心得和迁移经验,共同促进技术生态的健康发展。
|
||||
|
||||
请放心,即使进入维护模式,我们仍会确保EasyExcel的基本功能稳定运行,会进行Bug修复,但不再主动新增功能。我们相信,通过大家的共同努力,每一段代码、每一个项目都将继续在各自的领域发光发热,服务于更广泛的用户群体。
|
||||
再次感谢您对EasyExcel的支持与理解!期待在技术的广阔天地里,我们能以新的形式再度携手,共创辉煌。
|
||||
|
||||
祝您在未来的工作与学习中一切顺利!
|
||||
|
||||
阿里巴巴EasyExcel团队敬上
|
||||
|
||||
# 新手必读
|
||||
|
||||
* 官方网站:[https://easyexcel.opensource.alibaba.com/](https://easyexcel.opensource.alibaba.com/)
|
||||
* github地址:[https://github.com/alibaba/easyexcel](https://github.com/alibaba/easyexcel)
|
||||
* gitee地址:[https://gitee.com/easyexcel/easyexcel](https://gitee.com/easyexcel/easyexcel)
|
||||
|
||||
|
||||
# JAVA解析Excel工具
|
||||
|
||||
Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。
|
||||
easyexcel重写了poi对07版Excel的解析,一个3M的excel用POI sax解析依然需要100M左右内存,改用easyexcel可以降低到几M,并且再大的excel也不会出现内存溢出;03版依赖POI的sax模式,在上层做了模型转换的封装,让使用者更加简单方便
|
||||
|
||||
# 推荐 Chat2DB
|
||||
AI 驱动的数据库管理、数据分析工具,支持Mysql、pg、oracle、sqlserver、redis等10多种数据库
|
||||
* Github 地址: [https://github.com/chat2db/Chat2DB](https://github.com/chat2db/Chat2DB)
|
||||
* 官网:[https://chat2db-ai.com](https://chat2db-ai.com)
|
||||
<p align="center">
|
||||
<a href="https://chat2db.ai/" target="_blank">
|
||||
<img src="https://chat2db-cdn.oss-us-west-1.aliyuncs.com/website/img/cover.png" alt="Chat2DB" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
|
||||
# 网站
|
||||
* 官方网站:[https://easyexcel.opensource.alibaba.com/](https://easyexcel.opensource.alibaba.com/)
|
||||
* github地址:[https://github.com/alibaba/easyexcel](https://github.com/alibaba/easyexcel)
|
||||
* gitee地址:[https://gitee.com/easyexcel/easyexcel](https://gitee.com/easyexcel/easyexcel)
|
||||
|
||||
# 16M内存23秒读取75M(46W行25列)的Excel(3.2.1+版本)
|
||||
|
||||
|
|
@ -39,7 +47,7 @@ AI 驱动的数据库管理、数据分析工具,支持Mysql、pg、oracle、s
|
|||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>easyexcel</artifactId>
|
||||
<version>3.3.4</version>
|
||||
<version>4.0.3</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
|
|
@ -67,11 +75,31 @@ AI 驱动的数据库管理、数据分析工具,支持Mysql、pg、oracle、s
|
|||
不管`github`、`gitee`都会定期有人回答您的问题,比较紧急可以在提完`issue`以后在钉钉群艾特群主并发送`issue`地址帮忙解决。
|
||||
`QQ` 公司不让用,有时候也会去看,但是核心肯定还是在钉钉。
|
||||
|
||||
## 关注作者:程序员小獭
|
||||
## 也可以加入钉钉&QQ群来解决问题
|
||||
|
||||
可以加群交流
|
||||
|
||||

|
||||
加入钉钉或QQ群,看完公告可以获得帮助 。
|
||||
比较推荐钉钉群,`QQ` 公司不让用,当然QQ群也会有热心网友帮忙解决。
|
||||
[QQ1群(已满): 662022184](https://jq.qq.com/?_wv=1027&k=1T21jJxh)
|
||||
[QQ2群(已满): 1097936804](https://jq.qq.com/?_wv=1027&k=j5zEy6Xl)
|
||||
[QQ3群(已满): 453928496](https://qm.qq.com/cgi-bin/qm/qr?k=e2ULsA5A0GldhV2CXJ8sIbAyu9I6qqs7&jump_from=webapi)
|
||||
[QQ4群(已满): 496594404](https://qm.qq.com/cgi-bin/qm/qr?k=e_aVG1Q7gi0PJUBkbrUGAgbeO3kUEInK&jump_from=webapi)
|
||||
[QQ5群(已满): 451925680](https://jq.qq.com/?_wv=1027&k=6VHhvxyf)
|
||||
[QQ6群(已满): 784741035](https://jq.qq.com/?_wv=1027&k=BbLBIo9P)
|
||||
[QQ7群(已满): 667889383](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=XdTLw3Z3pr63VT0IkyoY-2t25TG7WxbG&authKey=gQKvTXipsjfUO1aNfL9zdHTfOmkqC6E%2BQ2zDg2jym8h3qXuQ7RtkpeAHeg9I4UhL&noverify=0&group_code=667889383)
|
||||
[QQ8群: 113968681](https://qm.qq.com/q/qwfl5RRBAG)
|
||||
[钉钉1群(已满): 21960511](https://qr.dingtalk.com/action/joingroup?code=v1,k1,cchz6k12ci9B08NNqhNRFGXocNVHrZtW0kaOtTKg/Rk=&_dt_no_comment=1&origin=11)
|
||||
[钉钉2群(已满): 32796397](https://qr.dingtalk.com/action/joingroup?code=v1,k1,jyU9GtEuNU5S0QTyklqYcYJ8qDZtUuTPMM7uPZTS8Hs=&_dt_no_comment=1&origin=11)
|
||||
[钉钉3群(已满): 33797247](https://qr.dingtalk.com/action/joingroup?code=v1,k1,3UGlEScTGQaHpW2cIRo+gkxJ9EVZ5fz26M6nW3uFP30=&_dt_no_comment=1&origin=11)
|
||||
[钉钉4群(已满): 33491624](https://qr.dingtalk.com/action/joingroup?code=v1,k1,V14Pb65Too70rQkEaJ9ohb6lZBZbtp6jIL/q9EWh9vA=&_dt_no_comment=1&origin=11)
|
||||
[钉钉5群(已满): 32134498](https://h5.dingtalk.com/circle/healthCheckin.html?dtaction=os&corpId=dingb9fa1325d9dccc3ecac589edd02f1650&5233a=71a83&cbdbhh=qwertyuiop)
|
||||
[钉钉6群(已满): 34707941](https://h5.dingtalk.com/circle/healthCheckin.html?dtaction=os&corpId=dingcf68008a1d443ac012d5427bdb061b7a&6ae36c3d-0c80-4=22398493-6c2a-4&cbdbhh=qwertyuiop)
|
||||
[钉钉7群(已满): 35235427](https://h5.dingtalk.com/circle/healthCheckin.html?dtaction=os&corpId=ding532b9018c06c7fc8660273c4b78e6440&167fb=ed003&cbdbhh=qwertyuiop)
|
||||
[钉钉8群(已满): 44752220](https://h5.dingtalk.com/circle/healthCheckin.html?dtaction=os&corpId=dingea96808beee421693fd4ba7542d6e5da&0380092a-fa46=a6a40905-7951&cbdbhh=qwertyuiop)
|
||||
[钉钉9群(已满): 11045002277](https://h5.dingtalk.com/circle/healthCheckin.html?dtaction=os&corpId=dinge338d2215891c0459c13cd6b2cb108a6&6972d=b92f9&cbdbhh=qwertyuiop)
|
||||
[钉钉10群(已满): 27360019755](https://qr.dingtalk.com/action/joingroup?code=v1,k1,v25LHn2liWmrWUKlkhIzOTcK7s7onp/sZP8mO5oIYSs=&_dt_no_comment=1&origin=11)
|
||||
[钉钉11群(已满):24330026964](https://qr.dingtalk.com/action/joingroup?code=v1,k1,63PjvTncu81oQ3X6XmGEJqnwQHCQxi/jaVlbUStq79o=&_dt_no_comment=1&origin=11)
|
||||
[钉钉12群(已满):27210038956](https://qr.dingtalk.com/action/joingroup?code=v1,k1,3mKi7VTGlYO+IsDX5n7sYYm2Qrlm220kMBPsJFzKRis=&_dt_no_comment=1&origin=11)
|
||||
[钉钉13群:83695000992](https://qr.dingtalk.com/action/joingroup?code=v1,k1,2JFUbWfxD1fGiq7LRW+mYjcK7s7onp/s1ZqOvfzkFGE=&_dt_no_comment=1&origin=11)
|
||||
|
||||
|
||||
# 维护者
|
||||
|
|
|
|||
|
|
@ -36,9 +36,5 @@
|
|||
<groupId>org.ehcache</groupId>
|
||||
<artifactId>ehcache</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
|
|
@ -34,7 +33,6 @@ import com.alibaba.excel.util.SheetUtils;
|
|||
import com.alibaba.excel.util.StringUtils;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
|
||||
import org.apache.poi.openxml4j.opc.OPCPackage;
|
||||
import org.apache.poi.openxml4j.opc.PackageAccess;
|
||||
|
|
@ -83,9 +81,6 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor {
|
|||
*/
|
||||
private final Map<Integer, CommentsTable> commentsTableMap;
|
||||
|
||||
private final Map<Integer, PackagePart> drawingMap;
|
||||
private final Map<Integer, PackagePart> drawingResMap;
|
||||
|
||||
public XlsxSaxAnalyser(XlsxReadContext xlsxReadContext, InputStream decryptedStream) throws Exception {
|
||||
this.xlsxReadContext = xlsxReadContext;
|
||||
// Initialize cache
|
||||
|
|
@ -113,20 +108,6 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor {
|
|||
sheetList = new ArrayList<>();
|
||||
sheetMap = new HashMap<>();
|
||||
commentsTableMap = new HashMap<>();
|
||||
drawingMap = MapUtils.newHashMap();
|
||||
drawingResMap = MapUtils.newHashMap();
|
||||
|
||||
// Reading images
|
||||
if (xlsxReadContext.readWorkbookHolder().getExtraReadSet().contains(CellExtraTypeEnum.IMAGE)) {
|
||||
List<PackagePart> drawingsPackagePartList = pkg.getPartsByName(
|
||||
Pattern.compile("/xl/drawings/drawing[0-9]+.xml"));
|
||||
if (CollectionUtils.isNotEmpty(drawingsPackagePartList)) {
|
||||
for (PackagePart drawingPackagePart : drawingsPackagePartList) {
|
||||
log.info("xx{}", drawingPackagePart);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<Integer, PackageRelationshipCollection> packageRelationshipCollectionMap = MapUtils.newHashMap();
|
||||
xlsxReadWorkbookHolder.setPackageRelationshipCollectionMap(packageRelationshipCollectionMap);
|
||||
|
||||
|
|
@ -142,7 +123,7 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor {
|
|||
if (xlsxReadContext.readWorkbookHolder().getExtraReadSet().contains(CellExtraTypeEnum.COMMENT)) {
|
||||
Comments comments = ite.getSheetComments();
|
||||
if (comments instanceof CommentsTable) {
|
||||
commentsTableMap.put(index, (CommentsTable)comments);
|
||||
commentsTableMap.put(index, (CommentsTable) comments);
|
||||
}
|
||||
}
|
||||
if (xlsxReadContext.readWorkbookHolder().getExtraReadSet().contains(CellExtraTypeEnum.HYPERLINK)) {
|
||||
|
|
@ -275,12 +256,6 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor {
|
|||
for (ReadSheet readSheet : sheetList) {
|
||||
readSheet = SheetUtils.match(readSheet, xlsxReadContext);
|
||||
if (readSheet != null) {
|
||||
xlsxReadContext.currentSheet(readSheet);
|
||||
parseXmlSource(sheetMap.get(readSheet.getSheetNo()), new XlsxRowHandler(xlsxReadContext));
|
||||
// Read comments
|
||||
readComments(readSheet);
|
||||
// Read image
|
||||
readImages(readSheet);
|
||||
try {
|
||||
xlsxReadContext.currentSheet(readSheet);
|
||||
parseXmlSource(sheetMap.get(readSheet.getSheetNo()), new XlsxRowHandler(xlsxReadContext));
|
||||
|
|
@ -297,28 +272,6 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor {
|
|||
}
|
||||
}
|
||||
|
||||
private void readImages(ReadSheet readSheet) {
|
||||
if (!xlsxReadContext.readWorkbookHolder().getExtraReadSet().contains(CellExtraTypeEnum.IMAGE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//xlsxReadContext.xlsxReadWorkbookHolder().getOpcPackage().getPart();
|
||||
//
|
||||
//CommentsTable commentsTable = commentsTableMap.get(readSheet.getSheetNo());
|
||||
//if (commentsTable == null) {
|
||||
// return;
|
||||
//}
|
||||
//Iterator<CellAddress> cellAddresses = commentsTable.getCellAddresses();
|
||||
//while (cellAddresses.hasNext()) {
|
||||
// CellAddress cellAddress = cellAddresses.next();
|
||||
// XSSFComment cellComment = commentsTable.findCellComment(cellAddress);
|
||||
// CellExtra cellExtra = new CellExtra(CellExtraTypeEnum.COMMENT, cellComment.getString().toString(),
|
||||
// cellAddress.getRow(), cellAddress.getColumn());
|
||||
// xlsxReadContext.readSheetHolder().setCellExtra(cellExtra);
|
||||
// xlsxReadContext.analysisEventProcessor().extra(xlsxReadContext);
|
||||
//}
|
||||
}
|
||||
|
||||
private void readComments(ReadSheet readSheet) {
|
||||
if (!xlsxReadContext.readWorkbookHolder().getExtraReadSet().contains(CellExtraTypeEnum.COMMENT)) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import java.util.Locale;
|
|||
import java.util.Map;
|
||||
|
||||
import com.alibaba.excel.util.MapUtils;
|
||||
import com.alibaba.excel.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Excel's built-in format conversion.Currently only supports Chinese.
|
||||
|
|
@ -20,8 +21,116 @@ import com.alibaba.excel.util.MapUtils;
|
|||
**/
|
||||
public class BuiltinFormats {
|
||||
|
||||
private static final String RESERVED = "reserved-";
|
||||
|
||||
public static short GENERAL = 0;
|
||||
|
||||
public static final String[] BUILTIN_FORMATS_ALL_LANGUAGES = {
|
||||
// 0
|
||||
"General",
|
||||
// 1
|
||||
"0",
|
||||
// 2
|
||||
"0.00",
|
||||
// 3
|
||||
"#,##0",
|
||||
// 4
|
||||
"#,##0.00",
|
||||
// 5
|
||||
"\"¥\"#,##0_);(\"¥\"#,##0)",
|
||||
// 6
|
||||
"\"¥\"#,##0_);[Red](\"¥\"#,##0)",
|
||||
// 7
|
||||
"\"¥\"#,##0.00_);(\"¥\"#,##0.00)",
|
||||
// 8
|
||||
"\"¥\"#,##0.00_);[Red](\"¥\"#,##0.00)",
|
||||
// 9
|
||||
"0%",
|
||||
// 10
|
||||
"0.00%",
|
||||
// 11
|
||||
"0.00E+00",
|
||||
// 12
|
||||
"# ?/?",
|
||||
// 13
|
||||
"# ??/??",
|
||||
// 14
|
||||
// The official documentation shows "m/d/yy", but the actual test is "yyyy/m/d".
|
||||
"yyyy/m/d",
|
||||
// 15
|
||||
"d-mmm-yy",
|
||||
// 16
|
||||
"d-mmm",
|
||||
// 17
|
||||
"mmm-yy",
|
||||
// 18
|
||||
"h:mm AM/PM",
|
||||
// 19
|
||||
"h:mm:ss AM/PM",
|
||||
// 20
|
||||
"h:mm",
|
||||
// 21
|
||||
"h:mm:ss",
|
||||
// 22
|
||||
// The official documentation shows "m/d/yy h:mm", but the actual test is "yyyy-m-d h:mm".
|
||||
"yyyy-m-d h:mm",
|
||||
// 23-36 No specific correspondence found in the official documentation.
|
||||
// 23
|
||||
null,
|
||||
// 24
|
||||
null,
|
||||
// 25
|
||||
null,
|
||||
// 26
|
||||
null,
|
||||
// 27
|
||||
null,
|
||||
// 28
|
||||
null,
|
||||
// 29
|
||||
null,
|
||||
// 30
|
||||
null,
|
||||
// 31
|
||||
null,
|
||||
// 32
|
||||
null,
|
||||
// 33
|
||||
null,
|
||||
// 34
|
||||
null,
|
||||
// 35
|
||||
null,
|
||||
// 36
|
||||
null,
|
||||
// 37
|
||||
"#,##0_);(#,##0)",
|
||||
// 38
|
||||
"#,##0_);[Red](#,##0)",
|
||||
// 39
|
||||
"#,##0.00_);(#,##0.00)",
|
||||
// 40
|
||||
"#,##0.00_);[Red](#,##0.00)",
|
||||
// 41
|
||||
"_(* #,##0_);_(* (#,##0);_(* \"-\"_);_(@_)",
|
||||
// 42
|
||||
"_(\"¥\"* #,##0_);_(\"¥\"* (#,##0);_(\"¥\"* \"-\"_);_(@_)",
|
||||
// 43
|
||||
"_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(@_)",
|
||||
// 44
|
||||
"_(\"¥\"* #,##0.00_);_(\"¥\"* (#,##0.00);_(\"¥\"* \"-\"??_);_(@_)",
|
||||
// 45
|
||||
"mm:ss",
|
||||
// 46
|
||||
"[h]:mm:ss",
|
||||
// 47
|
||||
"mm:ss.0",
|
||||
// 48
|
||||
"##0.0E+0",
|
||||
// 49
|
||||
"@",
|
||||
};
|
||||
|
||||
public static final String[] BUILTIN_FORMATS_CN = {
|
||||
// 0
|
||||
"General",
|
||||
|
|
@ -371,8 +480,26 @@ public class BuiltinFormats {
|
|||
public static final short MIN_CUSTOM_DATA_FORMAT_INDEX = 82;
|
||||
|
||||
public static String getBuiltinFormat(Short index, String defaultFormat, Locale locale) {
|
||||
if (index == null || index <= 0) {
|
||||
return defaultFormat;
|
||||
}
|
||||
|
||||
// Give priority to checking if it is the default value for all languages
|
||||
if (index < BUILTIN_FORMATS_ALL_LANGUAGES.length) {
|
||||
String format = BUILTIN_FORMATS_ALL_LANGUAGES[index];
|
||||
if (format != null) {
|
||||
return format;
|
||||
}
|
||||
}
|
||||
|
||||
// In other cases, give priority to using the externally provided format
|
||||
if (!StringUtils.isEmpty(defaultFormat) && !defaultFormat.startsWith(RESERVED)) {
|
||||
return defaultFormat;
|
||||
}
|
||||
|
||||
// Finally, try using the built-in format
|
||||
String[] builtinFormat = switchBuiltinFormats(locale);
|
||||
if (index == null || index < 0 || index >= builtinFormat.length) {
|
||||
if (index >= builtinFormat.length) {
|
||||
return defaultFormat;
|
||||
}
|
||||
return builtinFormat[index];
|
||||
|
|
|
|||
|
|
@ -17,12 +17,5 @@ public enum CellExtraTypeEnum {
|
|||
/**
|
||||
* Merge
|
||||
*/
|
||||
MERGE,
|
||||
|
||||
/**
|
||||
* Image
|
||||
*/
|
||||
IMAGE,
|
||||
|
||||
;
|
||||
MERGE,;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,20 @@
|
|||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
package com.alibaba.excel.util;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
|
@ -9,13 +26,16 @@ import java.time.LocalDateTime;
|
|||
import java.time.LocalTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.poi.ss.usermodel.DateUtil;
|
||||
import org.apache.poi.util.LocaleUtil;
|
||||
|
||||
/**
|
||||
* Date utils
|
||||
|
|
@ -63,6 +83,15 @@ public class DateUtils {
|
|||
|
||||
public static String defaultLocalDateFormat = DATE_FORMAT_10;
|
||||
|
||||
public static final int SECONDS_PER_MINUTE = 60;
|
||||
public static final int MINUTES_PER_HOUR = 60;
|
||||
public static final int HOURS_PER_DAY = 24;
|
||||
public static final int SECONDS_PER_DAY = (HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE);
|
||||
|
||||
// used to specify that date is invalid
|
||||
private static final int BAD_DATE = -1;
|
||||
public static final long DAY_MILLISECONDS = SECONDS_PER_DAY * 1000L;
|
||||
|
||||
private DateUtils() {}
|
||||
|
||||
/**
|
||||
|
|
@ -301,13 +330,75 @@ public class DateUtils {
|
|||
* @return Java representation of the date, or null if date is not a valid Excel date
|
||||
*/
|
||||
public static Date getJavaDate(double date, boolean use1904windowing) {
|
||||
//To calculate the Date, in the use of `org.apache.poi.ss.usermodel.DateUtil.getJavaDate(double, boolean,
|
||||
// java.util.TimeZone, boolean), Date when similar `2023-01-01 00:00:00.500`, returns the`2023-01-01
|
||||
// 00:00:01`, but excel in fact shows the `2023-01-01 00:00:00`.
|
||||
// `org.apache.poi.ss.usermodel.DateUtil.getLocalDateTime(double, boolean, boolean)` There is no problem.
|
||||
return Date.from(getLocalDateTime(date, use1904windowing).atZone(ZoneId.systemDefault()).toInstant());
|
||||
Calendar calendar = getJavaCalendar(date, use1904windowing, null, true);
|
||||
return calendar == null ? null : calendar.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get EXCEL date as Java Calendar with given time zone.
|
||||
* @param date The Excel date.
|
||||
* @param use1904windowing true if date uses 1904 windowing,
|
||||
* or false if using 1900 date windowing.
|
||||
* @param timeZone The TimeZone to evaluate the date in
|
||||
* @param roundSeconds round to closest second
|
||||
* @return Java representation of the date, or null if date is not a valid Excel date
|
||||
*/
|
||||
public static Calendar getJavaCalendar(double date, boolean use1904windowing, TimeZone timeZone, boolean roundSeconds) {
|
||||
if (!isValidExcelDate(date)) {
|
||||
return null;
|
||||
}
|
||||
int wholeDays = (int)Math.floor(date);
|
||||
int millisecondsInDay = (int)((date - wholeDays) * DAY_MILLISECONDS + 0.5);
|
||||
Calendar calendar;
|
||||
if (timeZone != null) {
|
||||
calendar = LocaleUtil.getLocaleCalendar(timeZone);
|
||||
} else {
|
||||
calendar = LocaleUtil.getLocaleCalendar(); // using default time-zone
|
||||
}
|
||||
setCalendar(calendar, wholeDays, millisecondsInDay, use1904windowing, roundSeconds);
|
||||
return calendar;
|
||||
}
|
||||
|
||||
|
||||
public static void setCalendar(Calendar calendar, int wholeDays,
|
||||
int millisecondsInDay, boolean use1904windowing, boolean roundSeconds) {
|
||||
int startYear = 1900;
|
||||
int dayAdjust = -1; // Excel thinks 2/29/1900 is a valid date, which it isn't
|
||||
if (use1904windowing) {
|
||||
startYear = 1904;
|
||||
dayAdjust = 1; // 1904 date windowing uses 1/2/1904 as the first day
|
||||
}
|
||||
else if (wholeDays < 61) {
|
||||
// Date is prior to 3/1/1900, so adjust because Excel thinks 2/29/1900 exists
|
||||
// If Excel date == 2/29/1900, will become 3/1/1900 in Java representation
|
||||
dayAdjust = 0;
|
||||
}
|
||||
calendar.set(startYear, Calendar.JANUARY, wholeDays + dayAdjust, 0, 0, 0);
|
||||
calendar.set(Calendar.MILLISECOND, millisecondsInDay);
|
||||
if (calendar.get(Calendar.MILLISECOND) == 0) {
|
||||
calendar.clear(Calendar.MILLISECOND);
|
||||
}
|
||||
if (roundSeconds) {
|
||||
// This is different from poi where you need to change 500 to 499
|
||||
calendar.add(Calendar.MILLISECOND, 499);
|
||||
calendar.clear(Calendar.MILLISECOND);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Given a double, checks if it is a valid Excel date.
|
||||
*
|
||||
* @return true if valid
|
||||
* @param value the double value
|
||||
*/
|
||||
|
||||
public static boolean isValidExcelDate(double value)
|
||||
{
|
||||
return (value > -Double.MIN_VALUE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Given an Excel date with either 1900 or 1904 date windowing,
|
||||
* converts it to a java.time.LocalDateTime.
|
||||
|
|
@ -470,31 +561,10 @@ public class DateUtils {
|
|||
case 0x14:
|
||||
case 0x15:
|
||||
case 0x16:
|
||||
// 27-36
|
||||
case 0x1b:
|
||||
case 0x1c:
|
||||
case 0x1d:
|
||||
case 0x1e:
|
||||
case 0x1f:
|
||||
case 0x20:
|
||||
case 0x21:
|
||||
case 0x22:
|
||||
case 0x23:
|
||||
case 0x24:
|
||||
// 45-47
|
||||
// 45-47
|
||||
case 0x2d:
|
||||
case 0x2e:
|
||||
case 0x2f:
|
||||
// 50-58
|
||||
case 0x32:
|
||||
case 0x33:
|
||||
case 0x34:
|
||||
case 0x35:
|
||||
case 0x36:
|
||||
case 0x37:
|
||||
case 0x38:
|
||||
case 0x39:
|
||||
case 0x3a:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,136 @@
|
|||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
package com.alibaba.excel.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.attribute.FileAttribute;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.apache.poi.util.DefaultTempFileCreationStrategy;
|
||||
import org.apache.poi.util.TempFileCreationStrategy;
|
||||
|
||||
import static org.apache.poi.util.TempFile.JAVA_IO_TMPDIR;
|
||||
|
||||
/**
|
||||
* In the scenario where `poifiles` are cleaned up, the {@link DefaultTempFileCreationStrategy} will throw a
|
||||
* java.nio.file.NoSuchFileException. Therefore, it is necessary to verify the existence of the temporary file every
|
||||
* time it is created.
|
||||
*
|
||||
* @author Jiaju Zhuang
|
||||
*/
|
||||
public class EasyExcelTempFileCreationStrategy implements TempFileCreationStrategy {
|
||||
/**
|
||||
* Name of POI files directory in temporary directory.
|
||||
*/
|
||||
public static final String POIFILES = "poifiles";
|
||||
|
||||
/**
|
||||
* To use files.deleteOnExit after clean JVM exit, set the <code>-Dpoi.delete.tmp.files.on.exit</code> JVM property
|
||||
*/
|
||||
public static final String DELETE_FILES_ON_EXIT = "poi.delete.tmp.files.on.exit";
|
||||
|
||||
/**
|
||||
* The directory where the temporary files will be created (<code>null</code> to use the default directory).
|
||||
*/
|
||||
private volatile File dir;
|
||||
|
||||
/**
|
||||
* The lock to make dir initialized only once.
|
||||
*/
|
||||
private final Lock dirLock = new ReentrantLock();
|
||||
|
||||
/**
|
||||
* Creates the strategy so that it creates the temporary files in the default directory.
|
||||
*
|
||||
* @see File#createTempFile(String, String)
|
||||
*/
|
||||
public EasyExcelTempFileCreationStrategy() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the strategy allowing to set the
|
||||
*
|
||||
* @param dir The directory where the temporary files will be created (<code>null</code> to use the default
|
||||
* directory).
|
||||
* @see Files#createTempFile(Path, String, String, FileAttribute[])
|
||||
*/
|
||||
public EasyExcelTempFileCreationStrategy(File dir) {
|
||||
this.dir = dir;
|
||||
}
|
||||
|
||||
private void createPOIFilesDirectory() throws IOException {
|
||||
// Create our temp dir only once by double-checked locking
|
||||
// The directory is not deleted, even if it was created by this TempFileCreationStrategy
|
||||
if (dir == null || !dir.exists()) {
|
||||
dirLock.lock();
|
||||
try {
|
||||
if (dir == null || !dir.exists()) {
|
||||
String tmpDir = System.getProperty(JAVA_IO_TMPDIR);
|
||||
if (tmpDir == null) {
|
||||
throw new IOException("System's temporary directory not defined - set the -D" + JAVA_IO_TMPDIR
|
||||
+ " jvm property!");
|
||||
}
|
||||
Path dirPath = Paths.get(tmpDir, POIFILES);
|
||||
dir = Files.createDirectories(dirPath).toFile();
|
||||
}
|
||||
} finally {
|
||||
dirLock.unlock();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public File createTempFile(String prefix, String suffix) throws IOException {
|
||||
// Identify and create our temp dir, if needed
|
||||
createPOIFilesDirectory();
|
||||
|
||||
// Generate a unique new filename
|
||||
File newFile = Files.createTempFile(dir.toPath(), prefix, suffix).toFile();
|
||||
|
||||
// Set the delete on exit flag, but only when explicitly disabled
|
||||
if (System.getProperty(DELETE_FILES_ON_EXIT) != null) {
|
||||
newFile.deleteOnExit();
|
||||
}
|
||||
|
||||
// All done
|
||||
return newFile;
|
||||
}
|
||||
|
||||
/* (non-JavaDoc) Created directory path is <JAVA_IO_TMPDIR>/poifiles/prefix0123456789 */
|
||||
@Override
|
||||
public File createTempDirectory(String prefix) throws IOException {
|
||||
// Identify and create our temp dir, if needed
|
||||
createPOIFilesDirectory();
|
||||
|
||||
// Generate a unique new filename
|
||||
File newDirectory = Files.createTempDirectory(dir.toPath(), prefix).toFile();
|
||||
|
||||
//this method appears to be only used in tests, so it is probably ok to use deleteOnExit
|
||||
newDirectory.deleteOnExit();
|
||||
|
||||
// All done
|
||||
return newDirectory;
|
||||
}
|
||||
}
|
||||
|
|
@ -12,7 +12,6 @@ import java.util.UUID;
|
|||
import com.alibaba.excel.exception.ExcelAnalysisException;
|
||||
import com.alibaba.excel.exception.ExcelCommonException;
|
||||
|
||||
import org.apache.poi.util.DefaultTempFileCreationStrategy;
|
||||
import org.apache.poi.util.TempFile;
|
||||
|
||||
/**
|
||||
|
|
@ -111,7 +110,7 @@ public class FileUtils {
|
|||
/**
|
||||
* Write inputStream to file
|
||||
*
|
||||
* @param file file
|
||||
* @param file file
|
||||
* @param inputStream inputStream
|
||||
*/
|
||||
public static void writeToFile(File file, InputStream inputStream) {
|
||||
|
|
@ -121,8 +120,8 @@ public class FileUtils {
|
|||
/**
|
||||
* Write inputStream to file
|
||||
*
|
||||
* @param file file
|
||||
* @param inputStream inputStream
|
||||
* @param file file
|
||||
* @param inputStream inputStream
|
||||
* @param closeInputStream closeInputStream
|
||||
*/
|
||||
public static void writeToFile(File file, InputStream inputStream, boolean closeInputStream) {
|
||||
|
|
@ -154,11 +153,8 @@ public class FileUtils {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public static void createPoiFilesDirectory() {
|
||||
File poiFilesPathFile = new File(poiFilesPath);
|
||||
createDirectory(poiFilesPathFile);
|
||||
TempFile.setTempFileCreationStrategy(new DefaultTempFileCreationStrategy(poiFilesPathFile));
|
||||
TempFile.setTempFileCreationStrategy(new EasyExcelTempFileCreationStrategy());
|
||||
}
|
||||
|
||||
public static File createCacheTmpFile() {
|
||||
|
|
@ -171,7 +167,6 @@ public class FileUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param directory
|
||||
*/
|
||||
public static File createDirectory(File directory) {
|
||||
|
|
|
|||
|
|
@ -21,11 +21,11 @@
|
|||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>5.3.31</version>
|
||||
<version>5.3.37</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jcl</artifactId>
|
||||
<groupId>*</groupId>
|
||||
<artifactId>*</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
|
@ -49,7 +49,7 @@
|
|||
<createDependencyReducedPom>true</createDependencyReducedPom>
|
||||
<!-- Make sure the transitive dependencies are written to the generated pom under <dependencies> -->
|
||||
<promoteTransitiveDependencies>true</promoteTransitiveDependencies>
|
||||
<artifactSet combine.self="override">
|
||||
<artifactSet>
|
||||
<includes>
|
||||
<include>org.springframework:spring-core</include>
|
||||
</includes>
|
||||
|
|
@ -63,6 +63,12 @@
|
|||
</includes>
|
||||
</filter>
|
||||
</filters>
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>org.springframework</pattern>
|
||||
<shadedPattern>com.alibaba.excel.support</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
|
|
|
|||
|
|
@ -29,17 +29,17 @@
|
|||
<dependency>
|
||||
<groupId>com.alibaba.fastjson2</groupId>
|
||||
<artifactId>fastjson2</artifactId>
|
||||
<version>2.0.29</version>
|
||||
<version>2.0.51</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<version>2.7.11</version>
|
||||
<version>2.7.18</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<version>2.7.11</version>
|
||||
<version>2.7.18</version>
|
||||
</dependency>
|
||||
|
||||
<!-- logback -->
|
||||
|
|
@ -61,7 +61,7 @@
|
|||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.2.12</version>
|
||||
<version>1.5.6</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
|
@ -74,7 +74,7 @@
|
|||
<includes>
|
||||
<include>/com/alibaba/easyexcel/test/core/**/*.java</include>
|
||||
</includes>
|
||||
<testFailureIgnore>true</testFailureIgnore>
|
||||
<testFailureIgnore>false</testFailureIgnore>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import lombok.Setter;
|
|||
public class DateFormatData {
|
||||
private String date;
|
||||
private String dateStringCn;
|
||||
private String dateStringCn2;
|
||||
private String dateStringUs;
|
||||
private String number;
|
||||
private String numberStringCn;
|
||||
|
|
|
|||
|
|
@ -3,9 +3,12 @@ package com.alibaba.easyexcel.test.core.dataformat;
|
|||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import com.alibaba.easyexcel.test.util.TestFileUtil;
|
||||
import com.alibaba.excel.EasyExcel;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
|
|
@ -21,6 +24,7 @@ import org.junit.jupiter.api.TestMethodOrder;
|
|||
@Slf4j
|
||||
public class DateFormatTest {
|
||||
|
||||
private static File file07V2;
|
||||
private static File file07;
|
||||
private static File file03;
|
||||
|
||||
|
|
@ -28,6 +32,8 @@ public class DateFormatTest {
|
|||
public static void init() {
|
||||
file07 = TestFileUtil.readFile("dataformat" + File.separator + "dataformat.xlsx");
|
||||
file03 = TestFileUtil.readFile("dataformat" + File.separator + "dataformat.xls");
|
||||
file07V2 = TestFileUtil.readFile("dataformat" + File.separator + "dataformatv2.xlsx");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -42,19 +48,39 @@ public class DateFormatTest {
|
|||
readUs(file03);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void t03Read() {
|
||||
List<Map<Integer, String>> dataMap = EasyExcel.read(file07V2).headRowNumber(0).doReadAllSync();
|
||||
log.info("dataMap:{}", JSON.toJSONString(dataMap));
|
||||
Assertions.assertEquals("15:00", dataMap.get(0).get(0));
|
||||
Assertions.assertEquals("2023-1-01 00:00:00", dataMap.get(1).get(0));
|
||||
Assertions.assertEquals("2023-1-01 00:00:00", dataMap.get(2).get(0));
|
||||
Assertions.assertEquals("2023-1-01 00:00:01", dataMap.get(3).get(0));
|
||||
Assertions.assertEquals("2023-1-01 00:00:00", dataMap.get(4).get(0));
|
||||
Assertions.assertEquals("2023-1-01 00:00:00", dataMap.get(5).get(0));
|
||||
Assertions.assertEquals("2023-1-01 00:00:01", dataMap.get(6).get(0));
|
||||
}
|
||||
|
||||
private void readCn(File file) {
|
||||
List<DateFormatData> list =
|
||||
EasyExcel.read(file, DateFormatData.class, null).locale(Locale.CHINA).sheet().doReadSync();
|
||||
for (DateFormatData data : list) {
|
||||
if (data.getDateStringCn() != null && !data.getDateStringCn().equals(data.getDate())) {
|
||||
log.info("date:cn:{},{}", data.getDateStringCn(), data.getDate());
|
||||
if (!Objects.equals(data.getDateStringCn(), data.getDate()) && !Objects.equals(data.getDateStringCn2(),
|
||||
data.getDate())) {
|
||||
log.info("date:cn:{},{},{}", data.getDateStringCn(), data.getDateStringCn2(), data.getDate());
|
||||
}
|
||||
if (data.getNumberStringCn() != null && !data.getNumberStringCn().equals(data.getNumber())) {
|
||||
log.info("number:cn{},{}", data.getNumberStringCn(), data.getNumber());
|
||||
}
|
||||
}
|
||||
for (DateFormatData data : list) {
|
||||
Assertions.assertEquals(data.getDateStringCn(), data.getDate());
|
||||
// The way dates are read in Chinese is different on Linux and Mac, so it is acceptable if it matches
|
||||
// either one.
|
||||
// For example, on Linux: 1-Jan -> 1-1月
|
||||
// On Mac: 1-Jan -> 1-一月
|
||||
Assertions.assertTrue(
|
||||
Objects.equals(data.getDateStringCn(), data.getDate()) || Objects.equals(data.getDateStringCn2(),
|
||||
data.getDate()));
|
||||
Assertions.assertEquals(data.getNumberStringCn(), data.getNumber());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import com.alibaba.excel.enums.CellExtraTypeEnum;
|
|||
import com.alibaba.excel.read.listener.PageReadListener;
|
||||
import com.alibaba.excel.read.listener.ReadListener;
|
||||
import com.alibaba.excel.read.metadata.ReadSheet;
|
||||
import com.alibaba.excel.read.metadata.holder.csv.CsvReadWorkbookHolder;
|
||||
import com.alibaba.excel.util.ListUtils;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
|
||||
|
|
@ -309,4 +310,28 @@ public class ReadTest {
|
|||
// 这里 只要,然后读取第一个sheet 同步读取会自动finish
|
||||
EasyExcel.read(fileName, new NoModelDataListener()).sheet().doRead();
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义修改csv配置
|
||||
*/
|
||||
@Test
|
||||
public void csvFormat() {
|
||||
String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.csv";
|
||||
try (ExcelReader excelReader = EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).build()) {
|
||||
// 判断是 csv 文件
|
||||
if (excelReader.analysisContext().readWorkbookHolder() instanceof CsvReadWorkbookHolder) {
|
||||
CsvReadWorkbookHolder csvReadWorkbookHolder = (CsvReadWorkbookHolder)excelReader.analysisContext()
|
||||
.readWorkbookHolder();
|
||||
// 设置成逗号分隔 当然默认也是逗号分隔
|
||||
// 这里要注意 withDelimiter 会重新生成一个 所以要放回去
|
||||
csvReadWorkbookHolder.setCsvFormat(csvReadWorkbookHolder.getCsvFormat().withDelimiter(','));
|
||||
}
|
||||
|
||||
// 拿到所有 sheet
|
||||
List<ReadSheet> readSheetList = excelReader.excelExecutor().sheetList();
|
||||
// 如果只想读取第一个 咋样传入参数即可
|
||||
//ReadSheet readSheet = EasyExcel.readSheet(0).build();
|
||||
excelReader.read(readSheetList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,9 +17,7 @@ import java.util.Map;
|
|||
import com.alibaba.easyexcel.test.demo.write.DemoData;
|
||||
import com.alibaba.easyexcel.test.util.TestFileUtil;
|
||||
import com.alibaba.excel.EasyExcel;
|
||||
import com.alibaba.excel.enums.CellExtraTypeEnum;
|
||||
import com.alibaba.excel.metadata.data.ReadCellData;
|
||||
import com.alibaba.excel.support.ExcelTypeEnum;
|
||||
import com.alibaba.excel.util.PositionUtils;
|
||||
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
|
||||
import com.alibaba.excel.write.metadata.style.WriteFont;
|
||||
|
|
@ -54,9 +52,8 @@ public class Lock2Test {
|
|||
File file = new File("/Users/zhuangjiaju/IdeaProjects/easyexcel/src/test/resources/converter/converter07.xlsx");
|
||||
|
||||
List<Object> list = EasyExcel.read(
|
||||
"/Users/zhuangjiaju/测试数据/imagetest.xlsx")
|
||||
"/Users/zhuangjiaju/Downloads/证券投资基金估值表_外贸信托-稳盈淳享37号集合资金信托计划_2024-07-23(1).xls")
|
||||
//.useDefaultListener(false)
|
||||
.extraRead(CellExtraTypeEnum.IMAGE)
|
||||
.sheet(0)
|
||||
.headRowNumber(0).doReadSync();
|
||||
LOGGER.info("数据:{}", list.size());
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
package com.alibaba.easyexcel.test.temp;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
|
@ -135,4 +138,11 @@ public class WriteV33Test {
|
|||
return list;
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void test4() throws Exception{
|
||||
Path path= Files.createTempFile(new File("/Users/zhuangjiaju/test/test0422/test/xx").toPath(),System.currentTimeMillis()+"",".jpg");
|
||||
System.out.println(path);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import java.util.List;
|
|||
|
||||
import com.alibaba.excel.EasyExcel;
|
||||
import com.alibaba.excel.support.cglib.beans.BeanMap;
|
||||
import com.alibaba.excel.support.cglib.core.DebuggingClassWriter;
|
||||
import com.alibaba.excel.util.BeanMapUtils;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
|
||||
|
|
@ -31,8 +32,8 @@ public class Xls03Test {
|
|||
@Test
|
||||
public void test2() {
|
||||
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
|
||||
//System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,
|
||||
// "/Users/zhuangjiaju/IdeaProjects/easyexcel/target");
|
||||
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,
|
||||
"/Users/zhuangjiaju/IdeaProjects/easyexcel/target");
|
||||
|
||||
CamlData camlData = new CamlData();
|
||||
//camlData.setTest("test2");
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import com.alibaba.easyexcel.test.core.large.LargeDataTest;
|
||||
import com.alibaba.easyexcel.test.util.TestFileUtil;
|
||||
import com.alibaba.excel.EasyExcel;
|
||||
import com.alibaba.excel.ExcelWriter;
|
||||
|
|
@ -31,7 +30,7 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
public class TempLargeDataTest {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(LargeDataTest.class);
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(TempLargeDataTest.class);
|
||||
private int i = 0;
|
||||
|
||||
private static File fileFill07;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
package com.alibaba.easyexcel.test.temp.poi;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.poi.ss.usermodel.DateUtil;
|
||||
import org.apache.poi.xssf.usermodel.XSSFCell;
|
||||
import org.apache.poi.xssf.usermodel.XSSFRow;
|
||||
import org.apache.poi.xssf.usermodel.XSSFSheet;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* 测试poi
|
||||
*
|
||||
* @author Jiaju Zhuang
|
||||
**/
|
||||
|
||||
public class PoiDateFormatTest {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(PoiDateFormatTest.class);
|
||||
|
||||
@Test
|
||||
public void read() throws IOException {
|
||||
String file
|
||||
= "/Users/zhuangjiaju/IdeaProjects/easyexcel/easyexcel-test/src/test/resources/dataformat/dataformat.xlsx";
|
||||
XSSFWorkbook xssfWorkbook = new XSSFWorkbook( file);
|
||||
XSSFSheet xssfSheet = xssfWorkbook.getSheetAt(0);
|
||||
LOGGER.info("一共行数:{}", xssfSheet.getLastRowNum());
|
||||
XSSFRow row = xssfSheet.getRow(7);
|
||||
XSSFCell cell = row.getCell(0);
|
||||
LOGGER.info("dd{}", cell.getDateCellValue());
|
||||
LOGGER.info("dd{}", cell.getNumericCellValue());
|
||||
|
||||
LOGGER.info("dd{}", DateUtil.isCellDateFormatted(cell));
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
package com.alibaba.easyexcel.test.temp.poi;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.poi.hssf.usermodel.HSSFPatriarch;
|
||||
import org.apache.poi.hssf.usermodel.HSSFPicture;
|
||||
import org.apache.poi.hssf.usermodel.HSSFPictureData;
|
||||
import org.apache.poi.hssf.usermodel.HSSFShape;
|
||||
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.xssf.usermodel.XSSFDrawing;
|
||||
import org.apache.poi.xssf.usermodel.XSSFPicture;
|
||||
import org.apache.poi.xssf.usermodel.XSSFPictureData;
|
||||
import org.apache.poi.xssf.usermodel.XSSFShape;
|
||||
import org.apache.poi.xssf.usermodel.XSSFSheet;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* 测试poi
|
||||
*
|
||||
* @author Jiaju Zhuang
|
||||
**/
|
||||
@Slf4j
|
||||
public class PoiImageTest {
|
||||
|
||||
@Test
|
||||
public void xls() throws Exception {
|
||||
|
||||
FileInputStream fis = new FileInputStream("/Users/zhuangjiaju/测试数据/imagetest.xls");
|
||||
HSSFWorkbook workbook = new HSSFWorkbook(fis);
|
||||
HSSFSheet sheet = workbook.getSheetAt(0);
|
||||
HSSFPatriarch patriarch = sheet.getDrawingPatriarch();
|
||||
|
||||
for (HSSFShape shape : patriarch.getChildren()) {
|
||||
if (shape instanceof HSSFPicture) {
|
||||
HSSFPicture picture = (HSSFPicture)shape;
|
||||
HSSFPictureData pictureData = picture.getPictureData();
|
||||
byte[] data = pictureData.getData();
|
||||
|
||||
log.info("图片:{}", data.length);
|
||||
}
|
||||
}
|
||||
|
||||
workbook.close();
|
||||
fis.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void xlsx() throws Exception {
|
||||
FileInputStream fis = new FileInputStream("/Users/zhuangjiaju/测试数据/imagetest.xlsx");
|
||||
XSSFWorkbook workbook = new XSSFWorkbook(fis);
|
||||
XSSFSheet sheet = workbook.getSheetAt(0);
|
||||
XSSFDrawing drawing = sheet.getDrawingPatriarch();
|
||||
|
||||
for (XSSFShape shape : drawing.getShapes()) {
|
||||
if (shape instanceof XSSFPicture) {
|
||||
XSSFPicture picture = (XSSFPicture)shape;
|
||||
XSSFPictureData pictureData = picture.getPictureData();
|
||||
byte[] data = pictureData.getData();
|
||||
log.info("图片:{}", data.length);
|
||||
log.info("图片:{}", pictureData.getPictureType());
|
||||
log.info("图片:{}", pictureData.getMimeType());
|
||||
log.info("图片:{}", pictureData.suggestFileExtension());
|
||||
//log.info("图片:{}", pictureData.suggestFileExtension());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
workbook.close();
|
||||
fis.close();
|
||||
}
|
||||
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,11 @@
|
|||
字符串标题,日期标题,数字标题
|
||||
字符串0,2020-01-01 01:01:00,1
|
||||
字符串1,2020-01-02 01:01:00,2
|
||||
字符串2,2020-01-03 01:01:00,3
|
||||
字符串3,2020-01-04 01:01:00,4
|
||||
字符串4,2020-01-05 01:01:00,5
|
||||
字符串5,2020-01-06 01:01:00,6
|
||||
字符串6,2020-01-07 01:01:00,7
|
||||
字符串7,2020-01-08 01:01:00,8
|
||||
字符串8,2020-01-09 01:01:00,9
|
||||
字符串9,2020-01-10 01:01:00,10
|
||||
|
43
pom.xml
43
pom.xml
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
|
||||
<properties>
|
||||
<revision>4.0.0-beta1</revision>
|
||||
<revision>4.0.3</revision>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<jdk.version>1.8</jdk.version>
|
||||
<gpg.skip>true</gpg.skip>
|
||||
|
|
@ -87,49 +87,50 @@
|
|||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Using the latest version of support simultaneously requires global use of the shade plugin, which is prone to errors, so changing to support will be lower than the overall -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>easyexcel-support</artifactId>
|
||||
<version>3.3.2</version>
|
||||
<version>3.3.4</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-csv</artifactId>
|
||||
<version>1.11.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi</artifactId>
|
||||
<version>5.2.3</version>
|
||||
<version>5.2.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi-ooxml</artifactId>
|
||||
<version>5.2.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>1.7.32</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-csv</artifactId>
|
||||
<version>1.10.0</version>
|
||||
<version>5.2.5</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ehcache</groupId>
|
||||
<artifactId>ehcache</artifactId>
|
||||
<version>3.9.9</version>
|
||||
<version>3.9.11</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.11.0</version>
|
||||
<version>2.16.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>1.7.36</version>
|
||||
</dependency>
|
||||
|
||||
<!-- provided -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.26</version>
|
||||
<version>1.18.32</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
|
@ -191,12 +192,12 @@
|
|||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.22.2</version>
|
||||
<version>3.3.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.2.4</version>
|
||||
<version>3.6.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
|
|
@ -236,11 +237,13 @@
|
|||
<exclude>com/alibaba/excel/metadata/DataFormatter.java</exclude>
|
||||
<exclude>com/alibaba/excel/util/DateUtils.java</exclude>
|
||||
<exclude>com/alibaba/excel/util/MapUtils.java</exclude>
|
||||
<exclude>com/alibaba/excel/util/EasyExcelTempFileCreationStrategy.java</exclude>
|
||||
<exclude>com/alibaba/excel/metadata/format/DataFormatter.java</exclude>
|
||||
<exclude>com/alibaba/excel/metadata/format/ExcelGeneralNumberFormat.java</exclude>
|
||||
<exclude>com/alibaba/excel/metadata/csv/CsvDataFormat.java</exclude>
|
||||
<exclude>com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java</exclude>
|
||||
<exclude>com/alibaba/excel/analysis/v07/handlers/sax/SharedStringsTableHandler.java</exclude>
|
||||
<exclude>com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
<executions>
|
||||
|
|
|
|||
23
update.md
23
update.md
|
|
@ -1,9 +1,24 @@
|
|||
# 4.0.0-beta1
|
||||
# 4.0.3
|
||||
|
||||
* `poi`由`4.1.2`升级到`5.2.3`
|
||||
* `commons-csv`由`1.9.0`升级到`1.10.0`
|
||||
* 兼容部分日期格式读取异常的问题
|
||||
|
||||
# 4.0.2
|
||||
|
||||
* 兼容某些特殊的xls: 修改了内置的样式导致判断样式错误
|
||||
* 重新加回 `commons-io`
|
||||
|
||||
# 4.0.1
|
||||
|
||||
* `commons-io` 修改为依赖 `poi`的版本
|
||||
* 修复临时目录被清理可能提示`NoSuchFileException`的异常
|
||||
|
||||
# 4.0.0
|
||||
|
||||
* `poi`由`4.1.2`升级到`5.2.5`
|
||||
* `commons-csv`由`1.1.0`升级到`1.10.0`
|
||||
* `slf4j-api`由`1.7.32`升级到`1.7.36`
|
||||
* `ehcache`由`3.9.9`升级到`3.10.8`
|
||||
* `ehcache`由`3.9.9`升级到`3.9.11`
|
||||
* 支持`jdk21`
|
||||
|
||||
# 3.3.4
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue