- 浏览: 5161834 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
silence19841230:
先拿走看看
SpringBoot2.0开发WebSocket应用完整示例 -
wallimn:
masuweng 写道发下源码下载地址吧!三个相关文件打了个包 ...
SpringBoot2.0开发WebSocket应用完整示例 -
masuweng:
发下源码下载地址吧!
SpringBoot2.0开发WebSocket应用完整示例 -
masuweng:
SpringBoot2.0开发WebSocket应用完整示例 -
wallimn:
水淼火 写道你好,我使用以后,图标不显示,应该怎么引用呢,谢谢 ...
前端框架iviewui使用示例之菜单+多Tab页布局
原文地址:http://school.cnd8.com/java/jiaocheng/15086.htm
首先说说现在我所知道的Java编辑Excel文件的两大开源工具:jakarta poi和JavaExcelAPI(简称JXL),这两套工具我都试用了一这段时间,感觉各有优劣吧。poi在某些细节有些小Bug并且不支持写入图片,其他方面都挺不错的;JXL就惨了,除了支持写入图片外,我暂时看不到它比POI好的地方,我碰到的主要的问题就是对公式支持不是很好,很多带有公式的Excel文件用JXL打开后,公式就丢失了(比如now(),today()),在网上看到其他大虾评论说JXL写入公式也有问题,另外,JXL操作Excel文件的效率比POI低一点。经过比较后,我选择了poi开发我的项目。
现在我要做的东西基本完成啦,我把这段时间使用poi的一些心得总结出来,希望能对和我碰到相同问题的朋友有所帮助,少熬几个夜,多点时间陪MM:),至于poi基本的使用方法,自己去看文档吧。
1、设置分页符的bug。
poi里的HSSFSheet类提供了setRowBreak方法可以设置Sheet的分页符。
Bug:假如你要设置分页符的Sheet是本来就有的,并且你没有在里面插入过分页符,那么调用setRowBreak时POI会抛出空指针的异常。
解决方法:在Excel里给这个sheet插入一个分页符,用POI打开后再把它删掉,然后你就可以随意插入分页符了。
假如sheet是由poi生成的则没有这个问题。我跟踪了setRowBreak的源代码,发现是Sheet.java下的PageBreakRecord rowBreaks这个变量在搞鬼,假如Sheet里原来没有分页符,开发这个模块的那位兄台忘了为这个对象new实例,所以只能我们先手工给Excel插入一个分页符来触发poi为rowBreaks创建实例。
2、如何拷贝行。
我在gmane.org的poi用户论坛翻遍了每个相关的帖子,找遍了api,也没看到一个拷贝行的方法,没办法,只能自己写:
//注:this.fWorkbook是一个HSSHWorkbook,请自行在外部new
public void copyRows(String pSourceSheetName, String pTargetSheetName, int pStartRow, int pEndRow, int pPosition)
{
HSSFRow sourceRow = null;
HSSFRow targetRow = null;
HSSFCell sourceCell = null;
HSSFCell targetCell = null;
HSSFSheet sourceSheet = null;
HSSFSheet targetSheet = null;
Region region = null;
int cType;
int i;
short j;
int targetRowFrom;
int targetRowTo;
if ((pStartRow == -1) (pEndRow == -1))
{
return;
}
sourceSheet = this.fWorkbook.getSheet(pSourceSheetName);
targetSheet = this.fWorkbook.getSheet(pTargetSheetName);
//拷贝合并的单元格
for (i = 0; i < sourceSheet.getNumMergedRegions(); i++)
{
region = sourceSheet.getMergedRegionAt(i);
if ((region.getRowFrom() >= pStartRow) && (region.getRowTo() <= pEndRow))
{
targetRowFrom = region.getRowFrom() - pStartRow + pPosition;
targetRowTo = region.getRowTo() - pStartRow + pPosition;
region.setRowFrom(targetRowFrom);
region.setRowTo(targetRowTo);
targetSheet.addMergedRegion(region);
}
}
//设置列宽
for (i = pStartRow; i <= pEndRow; i++)
{
sourceRow = sourceSheet.getRow(i);
if (sourceRow != null)
{
for (j = sourceRow.getFirstCellNum(); j < sourceRow.getLastCellNum(); j++)
{
targetSheet.setColumnWidth(j, sourceSheet.getColumnWidth(j));
}
break;
}
}
//拷贝行并填充数据
for (;i <= pEndRow; i++)
{
sourceRow = sourceSheet.getRow(i);
if (sourceRow == null)
{
continue;
}
targetRow = targetSheet.createRow(i - pStartRow + pPosition);
targetRow.setHeight(sourceRow.getHeight());
for (j = sourceRow.getFirstCellNum(); j < sourceRow.getLastCellNum(); j++)
{
sourceCell = sourceRow.getCell(j);
if (sourceCell == null)
{
continue;
}
targetCell = targetRow.createCell(j);
targetCell.setEncoding(sourceCell.getEncoding());
targetCell.setCellStyle(sourceCell.getCellStyle());
cType = sourceCell.getCellType();
targetCell.setCellType(cType);
switch (cType)
{
case HSSFCell.CELL_TYPE_BOOLEAN:
targetCell.setCellValue(sourceCell.getBooleanCellValue());
break;
case HSSFCell.CELL_TYPE_ERROR:
targetCell.setCellErrorValue(sourceCell.getErrorCellValue());
break;
case HSSFCell.CELL_TYPE_FORMULA:
//parseFormula这个函数的用途在后面说明
targetCell.setCellFormula(parseFormula(sourceCell.getCellFormula()));
break;
case HSSFCell.CELL_TYPE_NUMERIC:
targetCell.setCellValue(sourceCell.getNumericCellValue());
break;
case HSSFCell.CELL_TYPE_STRING:
targetCell.setCellValue(sourceCell.getStringCellValue());
break;
}
}
}
}
这个函数有两个问题暂时无法解决:
a、只能在同一个Workbook里面使用,跨Workbook总是拷不过去,不知道为什么?
b、由于在拷贝行时也把行高也拷过去了,假如往这些单元格里写入的数据长度超过单元格长度,那么他们不会自动调整行高!
有哪位大侠知道上面两个问题任意一个的解决方法,请第一时间通知我!!!
3、公式的问题。
POI对Excel公式的支持是相当好的,但是我发现一个问题,假如公式里面的函数不带参数,比如now()或today(),那么你通过getCellFormula()取出来的值就是now(ATTR(semiVolatile))和today(ATTR(semiVolatile)),这样的值写入Excel是会出错的,这也是我上面copyRow的函数在写入公式前要调用parseFormula的原因,parseFormula这个函数的功能很简单,就是把ATTR(semiVolatile)删掉,我把它的代码贴出来:
private String parseFormula(String pPOIFormula)
{
final String cstReplaceString = "ATTR(semiVolatile)"; //$NON-NLS-1$
StringBuffer result = null;
int index;
result = new StringBuffer();
index = pPOIFormula.indexOf(cstReplaceString);
if (index >= 0)
{
result.append(pPOIFormula.substring(0, index));
result.append(pPOIFormula.substring(index + cstReplaceString.length()));
}
else
{
result.append(pPOIFormula);
}
return result.toString();
}
至于为什么会出现ATTR(semiVolatile),希望哪位大侠现身跟我解释一下。
4、向Excel写入图片的问题。
我上poi论坛查相关帖子,得到两种结论:1、不支持写入图片;2、支持写入图片,通过EscherGraphics2d这个Class实现。于是我就去查EscherGraphics2d这个Class,发现这个Class提供了N个drawImage方法,喜出望外的我开始写代码,结果调了一天,一直看不到效果,黔驴技穷的我在万般无奈下只好跟踪进drawImage这个函数内部,经过N个函数调用后在最底层函数发现了最终答案(偶当场暴走!!!):
public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1,
int sx2, int sy2, Color bgColor, ImageObserver imageobserver)
{
if (logger.check( POILogger.WARN ))
logger.log(POILogger.WARN,"drawImage() not supported");
return true;
}
所以我强烈建议大家,以后使用第三方开发包一定尽量下载它的源代码,这样你在碰到问题时,看看它的的内部是怎么实现的,很多时候就可以不必重蹈我的覆辙了。既然POI不能写入图片,那我们只能把目光投向JXL,我用JXL写入图片功能是实现了,付出的代价是now()和today()这些函数丢失掉了,鱼与熊掌不能兼得吧,至于怎么解决JXL公式的问题,到下面这个帖子里和我一起守株待兔吧:
http://community.csdn.net/EXPert/topic/3569/3569340.XML?temp=.8480646
好了我所知道得就这些,我接触poi也才几星期时间,上面有些内容可能说得并不正确,希望各位大虾砸砖指正!
首先说说现在我所知道的Java编辑Excel文件的两大开源工具:jakarta poi和JavaExcelAPI(简称JXL),这两套工具我都试用了一这段时间,感觉各有优劣吧。poi在某些细节有些小Bug并且不支持写入图片,其他方面都挺不错的;JXL就惨了,除了支持写入图片外,我暂时看不到它比POI好的地方,我碰到的主要的问题就是对公式支持不是很好,很多带有公式的Excel文件用JXL打开后,公式就丢失了(比如now(),today()),在网上看到其他大虾评论说JXL写入公式也有问题,另外,JXL操作Excel文件的效率比POI低一点。经过比较后,我选择了poi开发我的项目。
现在我要做的东西基本完成啦,我把这段时间使用poi的一些心得总结出来,希望能对和我碰到相同问题的朋友有所帮助,少熬几个夜,多点时间陪MM:),至于poi基本的使用方法,自己去看文档吧。
1、设置分页符的bug。
poi里的HSSFSheet类提供了setRowBreak方法可以设置Sheet的分页符。
Bug:假如你要设置分页符的Sheet是本来就有的,并且你没有在里面插入过分页符,那么调用setRowBreak时POI会抛出空指针的异常。
解决方法:在Excel里给这个sheet插入一个分页符,用POI打开后再把它删掉,然后你就可以随意插入分页符了。
假如sheet是由poi生成的则没有这个问题。我跟踪了setRowBreak的源代码,发现是Sheet.java下的PageBreakRecord rowBreaks这个变量在搞鬼,假如Sheet里原来没有分页符,开发这个模块的那位兄台忘了为这个对象new实例,所以只能我们先手工给Excel插入一个分页符来触发poi为rowBreaks创建实例。
2、如何拷贝行。
我在gmane.org的poi用户论坛翻遍了每个相关的帖子,找遍了api,也没看到一个拷贝行的方法,没办法,只能自己写:
//注:this.fWorkbook是一个HSSHWorkbook,请自行在外部new
public void copyRows(String pSourceSheetName, String pTargetSheetName, int pStartRow, int pEndRow, int pPosition)
{
HSSFRow sourceRow = null;
HSSFRow targetRow = null;
HSSFCell sourceCell = null;
HSSFCell targetCell = null;
HSSFSheet sourceSheet = null;
HSSFSheet targetSheet = null;
Region region = null;
int cType;
int i;
short j;
int targetRowFrom;
int targetRowTo;
if ((pStartRow == -1) (pEndRow == -1))
{
return;
}
sourceSheet = this.fWorkbook.getSheet(pSourceSheetName);
targetSheet = this.fWorkbook.getSheet(pTargetSheetName);
//拷贝合并的单元格
for (i = 0; i < sourceSheet.getNumMergedRegions(); i++)
{
region = sourceSheet.getMergedRegionAt(i);
if ((region.getRowFrom() >= pStartRow) && (region.getRowTo() <= pEndRow))
{
targetRowFrom = region.getRowFrom() - pStartRow + pPosition;
targetRowTo = region.getRowTo() - pStartRow + pPosition;
region.setRowFrom(targetRowFrom);
region.setRowTo(targetRowTo);
targetSheet.addMergedRegion(region);
}
}
//设置列宽
for (i = pStartRow; i <= pEndRow; i++)
{
sourceRow = sourceSheet.getRow(i);
if (sourceRow != null)
{
for (j = sourceRow.getFirstCellNum(); j < sourceRow.getLastCellNum(); j++)
{
targetSheet.setColumnWidth(j, sourceSheet.getColumnWidth(j));
}
break;
}
}
//拷贝行并填充数据
for (;i <= pEndRow; i++)
{
sourceRow = sourceSheet.getRow(i);
if (sourceRow == null)
{
continue;
}
targetRow = targetSheet.createRow(i - pStartRow + pPosition);
targetRow.setHeight(sourceRow.getHeight());
for (j = sourceRow.getFirstCellNum(); j < sourceRow.getLastCellNum(); j++)
{
sourceCell = sourceRow.getCell(j);
if (sourceCell == null)
{
continue;
}
targetCell = targetRow.createCell(j);
targetCell.setEncoding(sourceCell.getEncoding());
targetCell.setCellStyle(sourceCell.getCellStyle());
cType = sourceCell.getCellType();
targetCell.setCellType(cType);
switch (cType)
{
case HSSFCell.CELL_TYPE_BOOLEAN:
targetCell.setCellValue(sourceCell.getBooleanCellValue());
break;
case HSSFCell.CELL_TYPE_ERROR:
targetCell.setCellErrorValue(sourceCell.getErrorCellValue());
break;
case HSSFCell.CELL_TYPE_FORMULA:
//parseFormula这个函数的用途在后面说明
targetCell.setCellFormula(parseFormula(sourceCell.getCellFormula()));
break;
case HSSFCell.CELL_TYPE_NUMERIC:
targetCell.setCellValue(sourceCell.getNumericCellValue());
break;
case HSSFCell.CELL_TYPE_STRING:
targetCell.setCellValue(sourceCell.getStringCellValue());
break;
}
}
}
}
这个函数有两个问题暂时无法解决:
a、只能在同一个Workbook里面使用,跨Workbook总是拷不过去,不知道为什么?
b、由于在拷贝行时也把行高也拷过去了,假如往这些单元格里写入的数据长度超过单元格长度,那么他们不会自动调整行高!
有哪位大侠知道上面两个问题任意一个的解决方法,请第一时间通知我!!!
3、公式的问题。
POI对Excel公式的支持是相当好的,但是我发现一个问题,假如公式里面的函数不带参数,比如now()或today(),那么你通过getCellFormula()取出来的值就是now(ATTR(semiVolatile))和today(ATTR(semiVolatile)),这样的值写入Excel是会出错的,这也是我上面copyRow的函数在写入公式前要调用parseFormula的原因,parseFormula这个函数的功能很简单,就是把ATTR(semiVolatile)删掉,我把它的代码贴出来:
private String parseFormula(String pPOIFormula)
{
final String cstReplaceString = "ATTR(semiVolatile)"; //$NON-NLS-1$
StringBuffer result = null;
int index;
result = new StringBuffer();
index = pPOIFormula.indexOf(cstReplaceString);
if (index >= 0)
{
result.append(pPOIFormula.substring(0, index));
result.append(pPOIFormula.substring(index + cstReplaceString.length()));
}
else
{
result.append(pPOIFormula);
}
return result.toString();
}
至于为什么会出现ATTR(semiVolatile),希望哪位大侠现身跟我解释一下。
4、向Excel写入图片的问题。
我上poi论坛查相关帖子,得到两种结论:1、不支持写入图片;2、支持写入图片,通过EscherGraphics2d这个Class实现。于是我就去查EscherGraphics2d这个Class,发现这个Class提供了N个drawImage方法,喜出望外的我开始写代码,结果调了一天,一直看不到效果,黔驴技穷的我在万般无奈下只好跟踪进drawImage这个函数内部,经过N个函数调用后在最底层函数发现了最终答案(偶当场暴走!!!):
public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1,
int sx2, int sy2, Color bgColor, ImageObserver imageobserver)
{
if (logger.check( POILogger.WARN ))
logger.log(POILogger.WARN,"drawImage() not supported");
return true;
}
所以我强烈建议大家,以后使用第三方开发包一定尽量下载它的源代码,这样你在碰到问题时,看看它的的内部是怎么实现的,很多时候就可以不必重蹈我的覆辙了。既然POI不能写入图片,那我们只能把目光投向JXL,我用JXL写入图片功能是实现了,付出的代价是now()和today()这些函数丢失掉了,鱼与熊掌不能兼得吧,至于怎么解决JXL公式的问题,到下面这个帖子里和我一起守株待兔吧:
http://community.csdn.net/EXPert/topic/3569/3569340.XML?temp=.8480646
好了我所知道得就这些,我接触poi也才几星期时间,上面有些内容可能说得并不正确,希望各位大虾砸砖指正!
发表评论
-
gradle编译错误:Could not find method compile() for arguments
2020-09-19 10:50 18522编译(IDEA+Gradle)一个别人的工程,出现一个 ... -
netty心跳检查之UDP篇
2019-09-15 08:50 2400部分UDP通信场景中,需要客户端定期发送心跳信息,以获取终 ... -
解决tomcat部署两个SpringBoot应用提示InstanceAlreadyExistsException
2019-06-30 11:49 3397两个SpringBoot应用部署在一个Tomcat中,单独 ... -
Eclipse配置MyBatis代码自动化功能
2019-06-29 10:16 17751.安装插件 Eclipse中,Help->Ecli ... -
vue.js中使用qrcode生成二维码
2019-05-20 00:00 7657一、安装包 npm install qrcodejs2 --s ... -
MySQL插入数据报错: Incorrect string value: '\xFD\xDE'
2019-03-31 23:19 1256我MySQL数据库用的uft-8字符集,插入数据一直很正常 ... -
vue自定义组件并双向绑定属性
2019-03-08 22:46 3258做了两个子组件,原理基本一样,一个是使用原生的select ... -
vue-router简单示例
2019-03-05 00:32 1153写个基本完整、稍有借鉴意义的示例,防止自己忘记。 &l ... -
“联通充值系统繁忙”轻松应对
2019-02-06 11:03 3973大过年的,联通充个值一直报“充值系统繁忙”。昨天晚上试了几 ... -
electron.js数据库应用---导航菜单(element-ui+mysql)
2019-02-05 21:33 2364一、环境搭建 略, ... -
electron.js数据库应用---入门(mysql+element-ui)
2019-01-27 23:19 7504我的机器:Windows10,64 ... -
SpringMVC 在controller层中注入成员变量request,是否线程安全
2018-12-17 21:17 2750@RestController public class ... -
VueJS 组件参数名命名与组件属性转化
2018-12-03 00:00 2077转自:https://www.cnblogs.com/meiy ... -
vue-resource拦截器实现token发送及检验自动化
2018-11-16 22:38 3079用了很长时间vue-resource,最近思考$http发 ... -
element-ui试用手记
2018-10-29 20:25 1748element-ui、iviewui都以vue.js为基础 ... -
iviewui中表格控件中render的使用示例
2018-07-07 16:46 9790示例了如何在表格中显示按钮,如何将代码转化为文字。 i ... -
Tomcat错误“Alias name tomcat does not identify a key entry”解决
2018-07-05 21:39 6576申请到了阿里云的证书后,下载、按照说明生成jks格式证书、 ... -
阿里云免费证书“fileauth.txt内容配置错误”解决
2018-07-05 20:43 5304最近研究微信小程序开发,上阿里云申请了个证书,使用文件验证 ... -
springboot2.0跨域配置
2018-07-04 22:11 5286springboot2.0跨域配置: 一、代码 ... -
微信小程序使用code换openid的方法(JAVA、SpringBoot)
2018-07-01 21:52 10401微信小程序序的代码中提示,使用code换取openid,但 ...
相关推荐
在使用POI读取Excel文档时,需要注意以下几点: 1. Excel文档的版本:POI支持多种Excel文档版本,包括xls、xlsx等。 2. 文档编码:POI支持多种文档编码,包括GBK、UTF-8等。 3. 单元格格式:POI支持多种单元格格式...
9. 使用POI的注意事项 在使用POI时,需要注意以下几点:首先,需要安装相关的依赖项。其次,需要 imports 相关的Package。最后,需要正确地使用POI的API。 10. POI的未来发展 POI的未来发展方向是继续完善文档...
标题中的“POI 3.8 Beta5”指的是Apache POI项目的一个版本,这是一个流行的开源Java库,用于读取、写入和修改Microsoft Office格式...通过掌握上述技巧和注意事项,可以有效地创建和操作Excel文件,满足各种业务需求。
使用Apache POI解析Excel时,有以下几个关键知识点: 1. **创建工作簿**:首先需要创建一个工作簿对象,这可以是HSSFWorkbook或XSSFWorkbook,根据需要处理的Excel文件类型来决定。 2. **添加工作表**:工作簿对象...
6. **性能注意事项** - 尽量使用SXSSF而非XSSF,因为XSSF在处理大数据时内存消耗更大。 - 避免在循环中创建不必要的对象,如字符串常量池可以减少内存分配。 - 使用适当的数据类型,例如数字而不是字符串,减少...
在了解如何使用Apache POI进行Excel导出之前,我们需要先了解几个重要的类: 1. **HSSFWorkbook**:代表一个Excel工作簿。 2. **HSSFSheet**:代表工作簿中的一个工作表。 3. **HSSFRow**:代表工作表中的一行。 4....
9. **最佳实践与注意事项**:教程可能还会分享一些使用POI的最佳实践,比如内存管理和性能优化,以及避免常见的错误和陷阱。 标签中的“源码”意味着可能会深入到Apache POI的源代码层面,讲解某些功能的工作原理或...
9. **注意事项**:处理大型Excel文件时,需要注意内存管理,因为POI会将整个工作簿加载到内存中。可以使用SXSSF API来实现流式处理,以降低内存消耗。 10. **版本更新**:Apache POI持续进行版本迭代,每次更新都会...
《POI数据预处理在ArcMap中的操作及注意事项》 POI(Point of Interest),即兴趣点数据,广泛应用于地理信息系统(GIS)中,用于表示特定地理位置,如餐馆、公园、医院等。对POI数据进行预处理是数据分析的重要...
在使用POI导出Excel时,需要注意以下几点: * 文件流的关闭:在导出EXCEL文件时,需要确保文件流的关闭,以免导致内存溢出和连接阻塞。 * 内存占用:在使用XSSF生成Excel 2007 OOXML (.xlsx)格式的文件时,需要注意...
根据提供的文件信息,我们可以总结出以下几个关键的知识点: ### ASP.NET 使用 NPOI 操作 Excel 的背景 在 Web 开发领域,尤其是使用 ASP.NET 进行开发时,经常需要处理 Excel 文件,例如导出数据到 Excel 或从 ...
### 使用POI插件的注意事项 在使用POI插件的过程中,还需要注意以下几个方面: - **兼容性问题**:确保所使用的POI版本与项目中其他库的兼容性,避免出现冲突。 - **性能优化**:对于大数据量的处理,需要注意内存...
通常,它会包含API概述、基本用法示例、注意事项以及可能遇到的问题的解决方案。对于初学者来说,这是一个非常重要的资源,因为它可以帮助快速理解和应用POI。 3. **淘宝优惠券.url**: 这可能是一个链接到淘宝优惠...
在IT行业中,尤其是在软件开发领域,使用VC++(Visual C++)进行文件操作是一项常见的任务。本主题聚焦于“VC操作Excel文件”,...同时,了解并熟练掌握相关API和注意事项,将有助于编写出高效、稳定且易于维护的代码。
4. **注意事项**: - 保持库版本的一致性,避免因不同版本间的不兼容问题导致错误。 - 大型文件处理时注意内存管理,因为POI可能会将整个工作簿加载到内存中。 - 使用流式处理方式可以降低内存消耗,特别是处理...
以下是关于使用Apache POI读取Excel表格文档的关键知识点: 1. **Apache POI的组成部分**: - HSSF:处理Excel的老式BIFF格式(XLS),适用于Excel 97-2007。 - XSSF:处理Excel的OOXML格式(XLSX),适用于Excel...
Java Word POI Demo是一个关于如何使用Java编程语言和Apache POI库来操作Microsoft Word文档的示例项目。Apache POI是开源项目,专门用于读取、写入和修改Microsoft Office格式的文件,包括Word(.doc和.docx)、...
本文将详细讲解如何在Android中实现对.xlsx和.xls格式的Excel文件进行读写,主要涉及的技术点包括文件操作、数据解析以及第三方库的使用。 一、文件操作基础 在Android中,文件操作通常涉及到以下几个步骤: 1. ...
使用 jxl 库时,需要注意以下几点: - jxl 支持的文件格式主要为 .xls,不支持 Office 2007 及以上版本的 .xlsx 文件。 - 读取和写入操作可能抛出 IOException,需要进行异常处理。 - 为了释放资源,读写完成后...
包含的“J2EE项目开发Excel导入导出操作组件源代码(附带说明文档)”很可能是项目开发的指南,详细解释了源码的使用方法、注意事项以及可能出现的问题,这对于理解和使用这些源码非常有帮助。 通过学习这个源码,...