【VB6|第18期】基于libxl导出Excel之导出失败的解决方案

日期:2023年6月12日
作者:Commas
签名:(ง •_•)ง 积跬步以致千里,积小流以成江海……
注释:如果您觉得有所帮助,帮忙点个赞,也可以关注我,我们一起成长;如果有不对的地方,还望各位大佬不吝赐教,谢谢^ - ^
1.01365 = 37.7834;0.99365 = 0.0255
1.02365 = 1377.4083;0.98365 = 0.0006


在这里插入图片描述



历史回顾:

《VB6使用libxl读写Excel浅谈(一)》


一、前言

基于libxl开发导出xlsx格式的Excel文件的功能,遇到一些奇奇怪怪的问题,导致提示“导出失败”,其实归根结底应该还是栈溢出导致的,但是问题隐藏的比较深,也是通过大量数据排查出来的,没有直接结论,而是带领大家一起分析一遍再解决问题,主要还是想分享这种分析的思想,且听我慢慢道来吧……

知识加油站:
xls格式:xls是Excel 97-2003版本中使用的文件格式。它是一种二进制文件格式,以二进制形式存储电子表格数据。xls格式的文件通常较大,并且在功能和兼容性方面存在一些限制。在Excel 2007及更高版本中,可以继续打开和编辑xls格式的文件,但在保存时会转换为xlsx格式。
xlsx格式:xlsx是Excel 2007及之后版本中引入的文件格式。它是基于XML(可扩展标记语言)的开放文件格式,以压缩形式存储电子表格数据。相比于xls格式,xlsx文件通常更小,并且支持更多的功能和选项。它提供了更好的数据恢复能力、更高的兼容性,并且支持使用新的功能,如条件格式、表格样式和更多的行列限制。

二、排查错误

一般情况下,在导出255个以内的sheet不会有问题,导出超过255个就可能会出现“导出失败”的情况,这个情况在xls格式的Excel文件确实是一个棘手的问题,在xlsx格式的Excel文件应该已经轻松解决了。于是我将问题锁定在了libxl库本身以及调用libxl上。至于为什么会怀疑libxl库本身,说多了那都是不愿回首的曾经啊,话不多说,还是回到正题上接着聊下去。功夫不负有心人,找到了几点错误,如下:

  • 【调用问题】:单元格样式的问题;
  • 【自身问题】:工作表表名sheetname超过15个中文字符或31个西文字符的问题;

三、解决问题

(3-1)调用问题的解决方案

当不设置单元格样式,不管数据多少都可以正常导出,这波操作直接把我整蒙了,难道要我导出没有样式的Excel文件给客户,这显然是不合乎常理的。冷静思考片刻,貌似这个库给我们的感觉就是,一直在创建指针,那会不会是指针创建太多了,栈被撑爆了。

接口函数:

'创建格式
Declare Function xlBookAddFormat Lib "lib4xl.dll" Alias "xlBookAddFormatA" (ByVal bookHandle As Long, ByVal formatHandle As Long) As Long
'创建字体
Declare Function xlBookAddFont Lib "lib4xl.dll" Alias "xlBookAddFontA" (ByVal bookHandle As Long, ByVal fontHandle As Long) As Long

每个单元格创建一个 formatHandlefontHandle 指针 ,如下:

'(1)创建格式与字体的指针
formatHandle = xlBookAddFormat(lngbook, 0)
fontHandle = xlBookAddFont(lngbook, 0)

'(2)给对应指针赋值(以下仅写几个样式作为示例而已)
'(2-1)单元格右边边框线
Call xlFormatSetBorderRight(formatHandle, 1)
'(2-2)字体格式
Call xlFontSetBold(fontHandle, 1)               '字体加粗
Call xlFontSetSize(fontHandle, FontSizs)        '字体大小
Call xlFormatSetFont(formatHandle, fontHandle)  '字体格式赋值到单元格格式

'(3)将指针样式赋值给单元格
'lngsheet:当前Excel中某个sheet的指针
'lngRow:单元格行数
'lngCol:单元格列数
'sFormula:单元格Excel公式
Call xlSheetWriteFormula(lngsheet, lngRow, lngCol, sFormula, formatHandle)

顺着这个思路,做了第一次尝试。
只创建一个 formatHandlefontHandle 指针,然后每个单元格重置指针的赋值,也就是上述代码的步骤(2),测试数据都可以正常导出了,欣喜之余,看了看导出的内容,发现所有单元格样式全部被设置为最后一次赋值的样式了,看来此法行不通;

大体方向对了,格式却变样了,所以又做了第二次尝试。
每种样式只创建一个 formatHandlefontHandle 指针,将创建好的 formatHandle 指针存于一个字典 dicFmtHdl 中,这样就极大减少了创建的指针的数量,同时又保证了每个单元格的样式。这次终于成功了,样本数据均通过测试;

小结一下,每个单元格都创建一个指针的话,那么指针数量是巨大的,同种类型的使用同一个指针是最佳的方式。只要指针数量控制在一定范围内,那么就可以正常导出Excel。libxl 的作者没有处理栈空间不足的问题,可能觉得指针就该发挥指针最大的用途吧。但是对于没有指针,或者弱指针类型的语言开发者来说可能会有些不太友好,毕竟开发思路会有些许差异的,适应适应就好,一切都是为了效率嘛。

(3-2)自身问题的解决方案

众所周知,工作表表名sheetname被定义不得超过31个字符,并无字节的限制。这么说来,那么超过31个字符就导出失败,极有可能是libxl库的问题,测试结果如下:

  • 字母+数字<=31
  • 中文<16(可以感受出来,1个中文等于2个“位置”)

以上条件是可以导出的,中文最大只能是15个字符,这极度不合理呀,这样我们只能另辟蹊径了,除了新建sheet可以命名之外,我们还可以对sheet进行重命名。

新建sheet

Declare Function xlBookAddSheet Lib "lib4xl.dll" Alias "xlBookAddSheetA" (ByVal bookHandle As Long, ByVal name As String, ByVal sheetHandle As Long) As Long

sheetname重命名

Declare Sub xlSheetSetName Lib "lib4xl.dll" Alias "xlSheetSetNameA" (ByVal sheetHandle As Long, ByVal name As String)

于是,新建的时候采用“sheet+数字”,让其不大于31字符,然后再重命名成自己想要的中文名称,如下所示:

'(1)新建sheet,让其以“字母+数字”命名sheetname,并控制其不得大于31个字符
lngsheet = xlBookAddSheet(lngbook, h, 0)

'(2)对sheet一堆操作
'此处省略一万行代码

'(3)将其命名成中文,最大可以达到31个中文字符,或者中文+字母+数字总共不得超过31个字符;
Call xlSheetSetName(lngsheet, "自己想要的中文名称")

正所谓关上一扇门的同时也打开一扇窗,虽然接口函数 xlBookAddSheet 有点小问题,不过重命名函数 xlSheetSetName 还是可以扛住,样本数据测试通过,完美手工^ - ^


版权声明:本文为博主原创文章,如需转载,请给出:
原文链接:https://blog.csdn.net/qq_35844043/article/details/130915267

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Commas.KM

码路共同进步,感恩一路有您

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值