一.概述

1. Excel 2003文件(即后缀为xls)是二进制文件,存储结构为复合文档,POI读取xls文件有两种方式

  1. 用户模式(usermodel):一次性将xls文件读入到内存,创建dom结构处理
  2. 事件模式(eventusermodel):以流的形式读取xls文件,读取xls文件占用相对较小的内存

2. 事件模式适用于愿意学习一点低级API结构的中间开发人员。它使用起来相对简单,但需要对Excel文件j结构有个基本了解。

二. 存储格式

2.1 Workbook document

1.Excel 2003文件称之为一个Workbook文档(Workbook document),一个Workbook document包含一个全局设置(Workbook globals)和至少一个Sheet

2.2 文档流Workbook Stream

Excel 2003文档(Workbook document)是以复合文档的格式存储,复合文档的原理就像一个文件系统,Excel整个文件对应的流文件称为“ Workbook Stream”,Workbook stream又被分成了许多子流(Substream)
  1. Workbook Globals Substream - Workbook globals对应的流,包含workbook的全局信息
  2. Sheet Substream - Sheet对应的流,包含一个Sheet的信息

2.3 子流SubStreams

文件流是按顺序存储的:
  1. 最先存储的是Workbook Globals Substream
  2. 接着是第一个Sheet Substream
  3. Sheet Substream的存储顺序是根据Excel中Sheet的顺序来的

三. 目录结构Directory

从上面我们知道以复合文档为存储格式的Excel 2003文件是以各种单独的子流SubStreams,各种子流SubStreams安按照一定的顺序构成整个文档流Workbook Stream.
那我们解析Excel 2003文件时怎么进入各种子流SubStream呢?
这就要靠目录结构Directory了:
  1. 目录结构Directory是复合文档一种内部控制流
  2. 目录结构Directory由一系列的目录条目Directory Entry组成
  3. 每一个目录条目Directory Entry都指向复合文档的一个仓库Storage或流Stream
  4. 目录条目Directory Entry根据对应仓库或流在文件流中出现的顺序被列举
  5. 目录条目Directory Entry的索引从0开始,其索引称为DirID,见下图
  6. DirID为0的表示一个特殊的目录条目,它代表根仓库条目 - root storage entry

3.1 目录条目按序列举

3.2 目录条目结构

  1. 每个目录条目指向一个仓库Storage或流Stream
  2. 每个目录条目Directory Entry固定大小为128字节
  3. 第一个目录条目是根仓库条目 - root storage Entry
  4. 第二个目录条目的名字是“Workbook”,它表示一个流
目录Directory将每个仓库Storage的直接成员(仓库或流)放在一个独立的红黑树中
  1. 根仓库Root Storage描述的是根仓库条目root storage entry ,由于它没有父目录条目,所以无需构建红黑树
  2. 根仓库的所有直接成员(Storage1、Stream1、Stream2、Storage2、Stream3、Stream4)将组成一颗红黑树,该树的根节点的DID记录在root storage entry中
  3. Storage1只有一个直接成员Stream1,Stream1将构成一颗红黑树,此树只有一个节点,Stream1的DID入口记录在Storage1目录条目中
  4. Storage2有3个直接成员,Stream21、Stream22、Stream23这3个直接成员将组成一颗红黑树,此树根节点的DID记录在Storage2的目录条目中
通过目录条目,就可以访问到对应的仓库或流

四. 记录Record

Excel 2003文件中各种子流SubStreams会被解析为各种记录Record,每种Record包含文档中各种内容或特定的数据
  • BOFRecord : 记录了Workbook或一个sheet的开始
  • EOFRecord : 记录了Workbook或一个sheet的结尾
  • STRecord : 记录了Excel中所有文件大院个的文本值
  • .......
org.apache.poi.hssf.record中记录各种Record类,每个Record实现类都有唯一标识符sid

每个Record的存储结构如下:
  1. Identifier:Record的标识符sid,POI读取到sid就知道将流解析成对应的Record
  2. size :记录了当前Record内容占据的大小,单位为字节
  3. content:当前Record的内容

@SuppressWarnings("unchecked")
private static final Class<? extends Record>[] recordClasses = new Class[] {  ArrayRecord.class,  AutoFilterInfoRecord.class,  BackupRecord.class,  BlankRecord.class,  BOFRecord.class,  BookBoolRecord.class,  BoolErrRecord.class,  BottomMarginRecord.class,  BoundSheetRecord.class,  CalcCountRecord.class,  CalcModeRecord.class,  CFHeaderRecord.class,  CFHeader12Record.class,  CFRuleRecord.class,  CFRule12Record.class,  ChartRecord.class,  ChartTitleFormatRecord.class,  CodepageRecord.class,  ColumnInfoRecord.class,  ContinueRecord.class,  CountryRecord.class,  CRNCountRecord.class,  CRNRecord.class,  DateWindow1904Record.class,  DBCellRecord.class,  DConRefRecord.class,  DefaultColWidthRecord.class,  DefaultRowHeightRecord.class,  DeltaRecord.class,  DimensionsRecord.class,  DrawingGroupRecord.class,  DrawingRecord.class,  DrawingSelectionRecord.class,  DSFRecord.class,  DVALRecord.class,  DVRecord.class,  EOFRecord.class,  ExtendedFormatRecord.class,  ExternalNameRecord.class,  ExternSheetRecord.class,  ExtSSTRecord.class,  FeatRecord.class,  FeatHdrRecord.class,  FilePassRecord.class,  FileSharingRecord.class,  FnGroupCountRecord.class,  FontRecord.class,  FooterRecord.class,  FormatRecord.class,  FormulaRecord.class,  GridsetRecord.class,  GutsRecord.class,  HCenterRecord.class,  HeaderRecord.class,  HeaderFooterRecord.class,  HideObjRecord.class,  HorizontalPageBreakRecord.class,  HyperlinkRecord.class,  IndexRecord.class,  InterfaceEndRecord.class,  InterfaceHdrRecord.class,  IterationRecord.class,  LabelRecord.class,  LabelSSTRecord.class,  LeftMarginRecord.class,  LegendRecord.class,  MergeCellsRecord.class,  MMSRecord.class,  MulBlankRecord.class,  MulRKRecord.class,  NameRecord.class,  NameCommentRecord.class,  NoteRecord.class,  NumberRecord.class,  ObjectProtectRecord.class,  ObjRecord.class,  PaletteRecord.class,  PaneRecord.class,  PasswordRecord.class,  PasswordRev4Record.class,  PrecisionRecord.class,  PrintGridlinesRecord.class,  PrintHeadersRecord.class,  PrintSetupRecord.class,  ProtectionRev4Record.class,  ProtectRecord.class,  RecalcIdRecord.class,  RefModeRecord.class,  RefreshAllRecord.class,  RightMarginRecord.class,  RKRecord.class,  RowRecord.class,  SaveRecalcRecord.class,  ScenarioProtectRecord.class,  SelectionRecord.class,  SeriesRecord.class,  SeriesTextRecord.class,  SharedFormulaRecord.class,  SSTRecord.class,  StringRecord.class,  StyleRecord.class,  SupBookRecord.class,  TabIdRecord.class,  TableRecord.class,  TableStylesRecord.class,  TextObjectRecord.class,  TopMarginRecord.class,  UncalcedRecord.class,  UseSelFSRecord.class,  UserSViewBegin.class,  UserSViewEnd.class,  ValueRangeRecord.class,  VCenterRecord.class,  VerticalPageBreakRecord.class,  WindowOneRecord.class,  WindowProtectRecord.class,  WindowTwoRecord.class,  WriteAccessRecord.class,  WriteProtectRecord.class,  WSBoolRecord.class,  // chart records  BeginRecord.class,  ChartFRTInfoRecord.class,  ChartStartBlockRecord.class,  ChartEndBlockRecord.class,  // TODO ChartFormatRecord.class,  ChartStartObjectRecord.class,  ChartEndObjectRecord.class,  CatLabRecord.class,  DataFormatRecord.class,  EndRecord.class,  LinkedDataRecord.class,  SeriesToChartGroupRecord.class,  // pivot table records  DataItemRecord.class,  ExtendedPivotTableViewFieldsRecord.class,  PageItemRecord.class,  StreamIDRecord.class,  ViewDefinitionRecord.class,  ViewFieldsRecord.class,  ViewSourceRecord.class,
};  

4.1 Record解析顺序

五. Workbook解析步骤

5.1 BOFRecord / EOFRecord

1.位置:org.apache.poi.hssf.record.BOFRecord、org.apache.poi.hssf.record.EOFRecord

2.BOFRecord表示Workbook或一个sheet的开始,EOFRecord表示Workbook或一个sheet的结尾

3.如图:

5.2 FormatRecord

1. 位置: org.apache.poi.hssf.record.FormatRecord
2. FormatRecord表示一个单元格样式,每个单元格样式对应一个索引和单元格字符串
3. 如图:

5.3 ExtendedFormatRecord

1. 位置: org.apache.poi.hssf.record.ExtendedFormatRecord
2. ExtendedFormatRecord记录了一个单元格的属性
  1. 单元格样式索引:XFIndex
  2. 单元格边框样式:border
  3. 单元格水平垂直样式:alignment
  4. 单元格填充色:fill

5.4 BoundSheetRecord

1. 位置:org.apache.poi.hssf.record.BoundSheetRecord
2. BoundSheetRecord记录了一个Sheet的名称:
  1. Excel中有几个Sheet,就有几个BoundSheetRecord对象
  2. BoundSheetRecord对应Sheet在Excel中出现顺序
3. 如图:

5.5 SSTRecord

1.位置:org.apache.poi.hssf.record.SSTRecord

2.SSTRecord中存储了在Excel中文本单元格中的文本值,文本单元格通过索引获取文本值

3.如图

六. WorkSheet解析步骤

6.1 BOFRecord/EOFRecord

1.  org.apache.poi.hssf.record.BOFRecord
2. type=16表示开始解析WorkSheet
3. 如图:

6.2 DimensionsRecord

1.位置:org.apache.poi.hssf.record.DimensionsRecord

2.DimensionsRecord存储了一个sheet的行列范围

DimensionsRecord 描述说明
field_1_first_row sheet中第一有效行行号
field_2_last_row sheet中最后有效行行号+1
field_3_first_col sheet中第一有效列列号
field_4_last_col sheet中最后有效列列号+1

3.如图

6.3 ColumnInfoRecord

1.位置:org.apache.poi.hssf.record.ColumnInfoRecord

2.ColumnInfoRecord存储了sheet中一列的信息

3.如图:

6.4 RowRecord

1.  位置: org.apache.poi.hssf.record.RowRecord
2. RowRecord记录了当前行行信息:
  1. 当前行索引
  2. 当前行是否隐藏
3. 如图:

6.5 LabelSSTRecord

1. 位置:org.apache.poi.hssf.record.LabelSSTRecord

2. LabelSSTRecord记录了一个sheet中的文本单元格

3. 如图:

Record 描述说明
NumberRecord 数值单元格
LabelSSTRecord 引用了SSTRecord中一个String类型的单元格值
BoolErrRecord 布尔或错误单元格,根据属性isError判断是布尔还是错误单元格
FormulaRecord 公式单元格
BlankRecord 空白单元格,单元格没有值,但是有单元格样式
StringRecord 存储文本公式的缓存结果
LabelRecord 只读,支持读取直接存储在单元格中的字符串,而不是存储在SSTRecord中,除了读取不要使用LabelRecord,应该使用SSTRecord替代

6.6 NumberRecord

1.  位置:  org.apache.poi.hssf.record.NumberRecord
2. NumberRecord记录了一个Sheet中的数值单元格:数值或日期
3. 如图:

6.7 BoolErrRecord

1. 位置:   org.apache.poi.hssf.record.BoolErrRecord
2. BoolErrRecord记录了一个Sheet中布尔单元格或错误单元格
3. 如图:

6.8 FormulaRecord

1. 位置:  org.apache.poi.hssf.record.FormulaRecord

2. FormulaRecord记录了一个Sheet中的公式单元格

3. 如图:

6.9 BlankRecord

1. 位置:  org.apache.poi.hssf.record.BlankRecord
2. BlankRecord记录了一个Sheet中一个空单元格:即单元格中没有值,但是单元格有单元格样式
3. 如图:

6.10 MergeCellsRecord

1.  位置:  org.apache.poi.hssf.record.MergeCellsRecord
2. MergeCellsRecord记录了一个Sheet中一个合并单元格
3. 如图:

七. 解析步骤

使用POI事件模式解析Excel 2003文件,需要先将Excel 2003文件转化为POI中POIFSFileSystem对象
  1. 实现接口HSSFListener,实现自己的监听器listener
  2. 通过Record。sid为某些特定的Record设置监听listener
  3. 根据Excel 2003文件路径获取该文件的输入流FileInputStream - in
  4. 根据输入流in创建POIFSFileSysytem实例对象poifs
  5. 第二个目录条目名字是Workbook,找到第二目录条目,根据对应的流创建一个输入流DocumentInputStream
  6. 根据输入流DocumentInputStream,解析为一个个记录Record
  7. 如果解析出的Record设置了监听,触发监听事件
  8. 处理监听器中事件

7.1 设置监听的Record

Excel XLS文档最终被解析为一个个Record,如果某些Record设置了监听器,会触发监听器事件
解析Excel XLS数据通常需要设置下面这些Record的监听器:
BOFRecord.sid,               // HSSFWorkbook、HSSFSheet的开始
EOFRecord.sid,              // HSSFWorkbook、HSSFSheet的结束
BoundSheetRecord.sid,       // BoundSheetRecord记录了sheetName
SSTRecord.sid,              // SSTRecord记录了所有Sheet的文本单元格的文本
DimensionsRecord.sid,       // DimensionsRecord记录了每个Sheet的有效起始结束行列索引
MergeCellsRecord.sid,       // MergeCellsRecord记录了每个Sheet中的合并单元格信息
ExtendedFormatRecord.sid,   // ExtendedFormatRecord记录了扩展的单元格样式
FormatRecord.sid,           // FormatRecord记录单元格样式信息
ColumnInfoRecord.sid,       // ColumnInfoRecord记录了Sheet中列信息,如列是否隐藏
RowRecord.sid,              // RowRecord记录了Sheet中行信息,如行索引,行是否隐藏
BlankRecord.sid,            // Sheet中空单元格,存在单元格样式
BoolErrRecord.sid,          // Sheet中布尔或错误单元格
FormulaRecord.sid,          // Sheet中公式单元格
LabelSSTRecord.sid,         // Sheet中文本单元格
NumberRecord.sid            // Sheet中数值单元格:数字单元格和日期单元格

7.2 org.apache.poi.poifs.filesystem.POIFSFileSystem类

  1. 根据fs可以获取到根目录条目DirectoryNode - root entry
  2. 根目录root entry根据Entry实体名Workbook获取对应的Entry
  3. 根据Workbook Entry创建该实体的输入流DocumentInputStream - ds
  4. 解析输入流ds,根据Excel XLS文档格式解析为各种Record
  5. 解析到设置监听器的Record,触发监听器时间listener,处理Record
/ xls文件的输入流
FileInputStream fin = newFileInputStream("C:\\Users\\Administrator\\Desktop\\测试.xls");
// 创建一个POIFSFileSystem实例
POIFSFileSystem poifs = newPOIFSFileSystem(fin);
// 从流中获取Excel的WorkBook流
InputStream workBookInputStream = poifs.createDocumentInputStream("Workbook");

7.3 org.apache.poi.hssf.eventusermodel.HSSFListener

HSSFListener是与HSSFRequest和HSSFEventFactory一起使用的接口

  • 用户应该实现接口HSSFListener,创建一个自己的监听器类Workbook
  • listener可以注册到HSSFRequest实例request中,用于监听特定的Record
  • 一个Record可以设置多个监听器,处理不同的事

7.4 org.apache.poi.hssf.eventusermodel.HSSFRequest

HSSFRequest中有一个Map,用于存储所有特定Record的监听器,一个Record可以设置多个监听器
HSSFRequest 类方法描述
addListener(HSSFListener lsnr, short sid) 为sid的记录record注册一个监听器lsnr
addListenerForAllRecords(HSSFListener lsnr)

为org.apache.poi.hssf.record.Record包中所有的记录注册一个监听器lsnr

不推荐用这种方法,影响性能

processRecord(Record rec)

由HSSFEventFactory调用,处理记录rec

记录rec可能注册了多个监听器,循环触发每个注册的监听器,处理记录record

7.5 org.apache.poi.hssf.eventusermodel.HSSFEventFactory

根据POIFSFileSystem实例解析Excel XLS文件的类
HSSFEventFactory 类方法描述
processWorkbookEvents(HSSFRequest req, POIFSFileSystem fs)

将一个文件处理为基本的Record事件

@param req 一个HSSFRequest实例,记录了Record的所有监听器

@param fs 包含WorkBook的POIFS文件系统

processWorkbookEvents(HSSFRequest req, DirectoryNode dir)

将一个文件处理为基本的Record事件

@param req 一个HSSFRequest实例,记录了Record的所有监听器

@param dir 包含WorkBook的DirectoryNode

processEvents(HSSFRequest req, InputStream in)

将一个文件处理为基本的Record事件

@param req 一个HSSFRequest实例,记录了Record的所有监听器

@param in 包含WorkBook的DirectoryNode的输入流

short abortableProcessWorkbookEvents(HSSFRequest req, POIFSFileSystem fs)

将一个文件处理为基本的Record事件

返回数值,如果监听器是继承AbortableHSSFListener,返回值不为0,则不会触发当前记录的其他监听器,
就会继续处理下一个记录
short abortableProcessWorkbookEvents(HSSFRequest req, DirectoryNode dir)

将一个文件处理为基本的Record事件

返回数值,如果监听器是继承AbortableHSSFListener,返回值不为0,则不会触发当前记录的其他监听器,
就会继续处理下一个记录
short abortableProcessEvents(HSSFRequest req, InputStream in)

将一个文件处理为基本的Record事件

返回数值,如果监听器是继承AbortableHSSFListener,返回值不为0,则不会触发当前记录的其他监听器,
就会继续处理下一个记录

八.一个事件模式实例

8.1 HSSFListener接口的实现类

package poi.hssf.event;
import org.apache.poi.hssf.eventusermodel.HSSFListener;
import org.apache.poi.hssf.record.BOFRecord;
import org.apache.poi.hssf.record.BoundSheetRecord;
import org.apache.poi.hssf.record.LabelSSTRecord;
import org.apache.poi.hssf.record.NumberRecord;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.RowRecord;
import org.apache.poi.hssf.record.SSTRecord;
public class HSSFListenerImpl implements HSSFListener {private SSTRecord sstrec;/*** This method listens for incoming records and handles them as required.* @param record    The record that was found while reading.*/public void processRecord(Record record) {switch (record.getSid()) {// the BOFRecord can represent either the beginning of a sheet or the workbookcase BOFRecord.sid:BOFRecord bof = (BOFRecord) record;if (bof.getType() == BOFRecord.TYPE_WORKBOOK) {System.out.println("处理 workbook");// assigned to the class level member} else if (bof.getType() == BOFRecord.TYPE_WORKSHEET) {System.out.println("处理sheet");}break;case BoundSheetRecord.sid:BoundSheetRecord bsr = (BoundSheetRecord) record;System.out.println("New sheet named: " + bsr.getSheetname());break;case RowRecord.sid:RowRecord rowrec = (RowRecord) record;System.out.println("Row found, first column at "+ rowrec.getFirstCol() + " last column at " + rowrec.getLastCol());break;case NumberRecord.sid:NumberRecord numrec = (NumberRecord) record;System.out.println("Cell found with value " + numrec.getValue()+ " at row " + numrec.getRow() + " and column " + numrec.getColumn());break;// SSTRecords store a array of unique strings used in Excel.case SSTRecord.sid:sstrec = (SSTRecord) record;for (int k = 0; k < sstrec.getNumUniqueStrings(); k++) {System.out.println("String table value " + k + " = " + sstrec.getString(k));}break;case LabelSSTRecord.sid:LabelSSTRecord lrec = (LabelSSTRecord) record;System.out.println("String cell found with value "+ sstrec.getString(lrec.getSSTIndex()));break;}}
}

8.2 Test

packagepoi.hssf.event;
importjava.io.FileInputStream;
importjava.io.IOException;
importjava.io.InputStream;
importorg.apache.poi.hssf.eventusermodel.HSSFEventFactory;
importorg.apache.poi.hssf.eventusermodel.HSSFRequest;
importorg.apache.poi.poifs.filesystem.POIFSFileSystem;
publicclass TestEventAPI {publicstatic void main(String[] args) throwsIOException {FileInputStream fin = newFileInputStream("C:\\Users\\Administrator\\Desktop\\测试.xls");try{POIFSFileSystem poifs = newPOIFSFileSystem(fin);try{// 从流中获取Excel的WorkBook流InputStream workBookInputStream = poifs.createDocumentInputStream("Workbook");try{HSSFRequest hssfRequest = newHSSFRequest();// 为所有的record注册一个监听器hssfRequest.addListenerForAllRecords(newHSSFListenerImpl());// 创建事件工厂HSSFEventFactory factory = newHSSFEventFactory();// 根据WorkBook输入流处理所有事件factory.processEvents(hssfRequest, workBookInputStream);}finally{workBookInputStream.close();}}finally{poifs.close();}}finally{// 一旦所有的监听器处理完成,关闭文件输入流fin.close();}}
}

POI事件模式读取Excel 2003文件相关推荐

  1. 解决POI事件驱动模式读取不到Java代码创建的Excel表格数据问题

    场景 使用POI官网上的事件驱动模式的示例方法,读取单sheet单次创建的Excel表格文件(.xlsx),Microsoft Excel和WPS Excel创建的表格文件可以正常读取数据,但是jav ...

  2. POI驱动模式读取Excel2007

    项目需要进行导入优化的时候,因为之前用poi旧版本读取excel时效率比较慢,后来了解的poi的驱动模式后,准备用来改造导入方法.在大批量数据面前效率提升比较明显(几百几千行数据时效率提供微弱) . ...

  3. java读取excel大文件

    在读取excel大文件的时候就不能再使用poi包下面的Workbook类,会造成OOM等问题. 我们常见的excel分为xlsx格式和csv格式.分别实现一下. xlsx格式处理. 需要的pom依赖: ...

  4. python xlrd读取excel-使用Python xlrd模块读取Excel格式文件的方法

    这是一篇关于如何使用Python xlrd模块读取Excel格式文件的方法的文章,下面的python代码中使用 了xlrd模块的方法,这样就能够很方便的读取 excel 文件内容.同是这个xlrd模块 ...

  5. excel2003 java_java 读取 excel 2003 或 excel 2007

    # re: java 读取 excel 2003 或 excel 2007 2012-10-15 22:44 惠万鹏 public class DateUtil { /** * * Descripti ...

  6. pandas玩转excel-> (2)如何利用pandas读取excel数据文件

    pandas玩转excel-> (2)如何利用pandas读取excel数据文件 import pandas as pd #将excel文件读到内存中,形成dataframe,并命名为peopl ...

  7. python读取Excel表格文件

    python读取Excel表格文件,例如获取这个文件的数据 python读取Excel表格文件,需要如下步骤: 1.安装Excel读取数据的库-----xlrd 直接pip install xlrd安 ...

  8. 基于Python读取Excel表格文件数据并转换为字典dict格式

      有时我们需要将一个Excel表格文件中的全部或一部分数据导入到Python并转换为字典格式,如何实现呢?   我们以如下所示的一个表格(.xlsx格式)作为简单的示例.其中,表格共有两列,第一列为 ...

  9. 使用Apache下poi创建和读取excel文件

    一:使用apache下poi创建excel文档 1 @Test 2 /* 3 * 使用Apache poi创建excel文件 4 */ 5 public void testCreateExcel() ...

最新文章

  1. 反向telnet连接
  2. PyCharm如何集成PyQt
  3. 基本概念-编写第一个C程序
  4. 推荐一个markdown格式转html格式的开源JavaScript库
  5. leetCode 53. maximum subarray
  6. rockmq运维指令_RocketMQ 运维指令
  7. input子系统基础之按键4——输入核心层源码分析
  8. 信息学奥赛一本通 2057:【例3.9 】星期几
  9. [JLOI2009]二叉树问题
  10. HttpUtils请求工具类
  11. Python之网络数据采集入门常用模块初识
  12. javascript案例,专辑前6名
  13. RNDIS的usb网卡功能调试
  14. 运动目标检测之光流法(2):金字塔Lucas-Kanade算法
  15. 怎么申请https证书
  16. passenger+nginx框架部署
  17. 网站优化相关理论概述
  18. cocos2dx创造精灵的五种方法
  19. JAVA工程师面试题目大全_绝对值得看
  20. 容器-Docker《三》容器管理

热门文章

  1. Springboot 服务端为App集成支付宝支付
  2. android 动画变成素材,AE技法-把AE动画转换成Android原生动画,撂倒GIF做动画
  3. ae制h5文字动画_大杀器Bodymovin和Lottie:把AE动画转换成HTML5/Android/iOS原生动画
  4. 科维的时间管理法—《可以量化的管…
  5. 杀戮尖塔(Slay the Spire) mod制作 --- 1
  6. rm: cannot remove `xxx’: Operation not permitted的解决方法
  7. 我的创业你也可以复制:财务做账中常见的问题
  8. 兴业数金C语言笔试,2021兴业数金校园招聘C语言开发工程师职位
  9. web前端工程师基础知识点
  10. 优盘连接时显示参数错误请问咋才能修复