C++用來操作Excel的方法很多,但是涉及到跨平台,同時又要對Excel的讀寫操作兼顧,而且免費的庫,那應該是要用xlslib和libxls了。由於技術比較菜,折騰這個折騰了一個星期了。最開始是使用QtXlsx庫,而且這個庫對於Qt來說操作不要太方便,但是研究了一下才發現,這個庫是基於Qt5寫的,而我們還在用Qt484開發,要想把里面的內容改一下適配Qt4,難度和工作量還是挺大的,因此作罷。后又轉投QAxObject類對Excel的COM組件進行操作,這種方法倒是實現了,但是COM組件這個是Windows平台特有的,Linux上也是沒什么指望了。因此開始研究了xlslib庫和xlslib庫,xlslib庫只能寫Excel文件,libxls庫只能讀Excel文件。關於這兩個庫的編譯及說明網上一大堆,而且庫文件本身存在的問題也有。對於xlslib庫的使用官網上有比較詳盡的Quick Reference Guide,使用起來還挺方便的,因此先寫一下xlslib庫的詳細編譯及使用步驟,然后再寫一下libxls庫的編譯及使用步驟,希望對新入門的猿類有所助。
一、xlslib庫的編譯
1、首先從網站下載xlsLib庫源碼,版本為xlslib-package-2.5.0.zip(1.1MB)
地址:http://sourceforge.net/projects/xlslib/
2、將文件解壓后得到兩個文件夾:OpenEXR、xlslib。在xlslib\xlslib\build路徑中有各版本的VS編譯工程,以VS2008為例,打開工程后得到7個項目
其中,xlslib_dll項目編譯動態庫文件,編譯后得到dll和lib文件;
xlslib_lib項目編譯靜態庫文件,編譯后得到lib文件
xlslib-testC為xlslib庫的C語言應用Example
xlslib-textCPP為xlslib庫的C++應用Example
3、生成xlslib_dll,直接編譯會出現很多問題,在錯誤列表中會提示"xlslib\***.h"的頭文件找不到。原因是:頭文件目錄未包含進來。將頭文件路徑添加到工程。按如下方法添加:
接下來編譯,會出現兩個sheet_notes的錯誤。sheet_notes 非法重定義,或構造函數不能返回類型。如下圖:
這個錯誤的原因是,結構體sheet_notes的類型名稱和變量命令相同了。由於C/C++中,結構體可以有構造函數,所以,這兩個名稱是不能相同的。編譯器會將成員變量當成是構造函數,從而報錯。
解決辦法是,修改其中一個的名字,只要兩個不相同就ok。經過搜索發現成員變量sheet_notes被用到只有3次,而結構體被用到很多次。於是,修改成員變量。
再編譯,還會提示一個 function_property 的錯誤
修改代碼如下:
再編譯,通過,ok。成功生成dll和lib兩種庫。通過更改以上錯誤之后,親試生成靜態庫,動態庫,64位庫文件及32位庫文件均成功。
4、測試工程中使用該庫。將頭文件及庫文件分別放入工程中,靜態庫,動態庫及頭文件分別放入以下位置
其中xlslib目錄下分別包含以下文件,
xlslib\xlslib目錄中放入解壓出來的源碼..\xlslib\xlslib\src\xlslib路徑下的頭文件
xlslib\common目錄中放入解壓出來的源碼..\xlslib\xlslib\src\common路徑下的頭文件,同時將..\xlslib\xlslib\src中的xlslib.h頭文件加入到common文件夾中
xlslib\oledoc目錄中放入解壓出來源碼..\xlslib\xlslib\src\oledoc路徑下的頭文件
5、在工程包含頭文件中加入如下路徑
在工程引用的庫文件中加入如下路徑及引用
6、編譯測試工程,出現“__FRAMEWORK__”相關的錯誤:error C2535: “xlslib_core::format_t::format_t錯誤原因:
QT的工程配置中配置屬性C/C++語言將wchar_t視為內置類型“是/否”和xlslib_lib的沖突,所以編譯的時候出現錯誤。如果在QT的設置里面wchar_t視為內置類型由否修改為是,則QString::toStdWstring()無法使用。除非重新編譯QT源碼。而報錯的地方原因是編譯器認為Ustring和u16string是一樣的。所以認為重復定義
1 format_t(CGlobalRecords&gRecords, const xlslib_strings::ustring& fmtstr); 2 #ifndef __FRAMEWORK__ 3 format_t(CGlobalRecords&gRecords, const xlslib_strings::u16string& fmtstr); 4 #endif
解決方法:將所有
1 #ifndef __FRAMEWORK__ 2 format_t(CGlobalRecords&gRecords, const xlslib_strings::u16string& fmtstr); 3 #endif
全部注釋掉。同時將CPP中的定義也注釋掉,最后編譯通過。
xlslib庫的使用參考鏈接:https://github.com/LeslieZhu/books/blob/master/share/xlslibRefGuide.pdf
二、libxls庫的編譯及使用
1、從網站上下載源碼,最新版本libxls-1.4.0.zip
地址:http://sourceforge.net/projects/libxls/
2、解壓后,在Linux下的安裝方法,親測可行,生成的.a文件和.la文件:
./configure
make
make install
在Window下則需要通過mingw編譯器先編譯成.a文件,然后將.a文件拆開成.o文件,再將.o文件生成.def文件,最后在VS中使用.o文件和.def文件即可生成dll文件和lib文件。
3、下載安裝cygwin軟件,在windows上安裝,32位機器下載地址https://cygwin.com/setup-x86.exe,64位機器下載地址https://cygwin.com/setup-x86_64.exe。下載完成后,安裝cygwin.exe,安裝后選擇安裝以下組件:
make
mingw64-i686-binutils
mingw64-i686-gcc-core
mingw64-i686-gcc-g++
mingw64-i686-win-iconv
4、等待cygwin安裝完成后,將libxls源碼放到cygwin目錄中,cygwin目錄為安裝時選擇的安裝路徑,選擇將源碼放入/home/用戶名/opt/下,opt文件夾需要手動新建(任意文件夾都行)。
5、在libxls的根目錄(../home/fbi/opt/libxls)修改configure中的DEFS定義為:
DEFS=-DHAVE_CONFIG_H -D_GNU_SOURCE
(用來解決make時候的警告warning: implicit declaration of function 'asprintf' [-Wimplicit-function-declaration]),cd到源文件目錄下,然后在cygwin中執行如下命令對configure進行配置:
32位:CC='i686-w64-mingw32-gcc' ./configure --host=i686-w64-mingw32 --build=i686-w64-mingw32
64位:CC='x86_64-w64-mingw32-gcc' ./configure --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32
6、以上步驟執行后會生成Makefile文件,直接使用make、make intall命令進行編譯安裝。只要make過程沒出錯即可在../usr/local/xlslib目錄下看到生成的bin、include、lib文件夾,在bin目錄中為xls2csv.exe,但是沒法成功運行,提示缺少iconv.dll,在usr\i686-w64-mingw32\sys-root\mingw\bin下即可找到,將該文件復制到bin目錄下,xls2csv.exe即可正常運行。include文件夾中為調用該庫時需要用到的頭文件,lib目錄下為libxlsreader.a和libxlsreader.la文件,此時需要通過.a文件轉換出windows上運行需要用到的dll文件和lib文件以及鏈接過程中需要用到的def文件。
7、接下來利用生成的libxlsreader.a來生成需要的dll、lib及def文件。
32位:在cygwin命令行下執行“i686-w64-mingw32-ar x libxlsreader.a”提取a中的.o文件
64位:在cygwin命令行下執行“x86_64-w64-mingw32-ar x libxlsreader.a”提取a中的.o文件
然后利用.o文件來生成dll文件和def文件,具體命令如下:
32位:i686-w64-mingw32-gcc -shared -o libxls.dll *.o -Wl,--export-all-symbols,--output-def,libxls.def -liconv
64位:x86_64-w64-mingw32-gcc -shared -o libxls.dll *.o -Wl,--export-all-symbols,--output-def,libxls.def -liconv
最后利用dll和def通過visual studio的lib來得到鏈接需要的lib文件,打開visual studio 命令提示,然后cd /d G:\cygwin64\usr\local\libxls\lib切換目錄到dll所在目錄並執行:
32位:lib /machine:X86 /def:libxls.def
64位:lib /machine:X64 /def:libxls.def
執行完以上步驟后,即可在cygwin64\usr\local\libxls\lib目錄下看到生成的lib文件和dll文件,同時在cygwin64\usr\local\libxls\include目錄下為調用庫時需要包含的頭文件。
以下為注意事項,在編譯過程中出可能出現xlstypes.h文件報錯,提示__attribute__相關的錯誤,主要是由於linux和windows系統對數據格式定義目的差異造成,可將xlstypes.h文件修改如下:
#ifndef XLS_TYPES_INC #define XLS_TYPES_INC #include <stdint.h> typedef unsigned char BYTE; typedef uint16_t WORD; typedef uint32_t DWORD; #ifdef NO_ALIGN typedef uint16_t WORD_UA; typedef uint32_t DWORD_UA; #else #ifdef _WIN32 typedef __declspec(align(1)) uint16_t WORD_UA; typedef __declspec(align(1)) uint32_t DWORD_UA; #else typedef uint16_t WORD_UA __attribute__ ((aligned (1))); // 2 bytes typedef uint32_t DWORD_UA __attribute__ ((aligned (1))); // 4 bytes #endif /* _WIN32 */ #endif /* NO_ALIGN */ #endif /* XLS_TYPES_INC*/
8、libxls進行配置到工程中,先將\usr\local\libxls\include文件夾中的頭文件放入到新的工程中的include文件夾中,在工程的設置中添加如下附加包含目錄:
然后將lib文件放入工程目錄下的lib文件夾中,並配置附加庫目錄如下:
9、在工程中添加頭文件如下:
#include "libxls/xlsstruct.h"
#include "libxls/xls.h"
using namespace xls;
務必將xlsstruct.h文件包含在xls.h頭文件之前,否則可能報錯。
到這里就結束了xlslib和libxls庫的編譯和配置了。libxls庫的使用並沒有相關文檔,目前博客中的說明也不是太多,等用用之后總結一下,再重新寫篇介紹的博客吧。搞完這個庫也參考了不少博客,就不一一列出參考了,感謝他們的無私奉獻。
最后想到一點,在libxls庫的xls.h頭文件中發現其中只有讀Excel的一些函數聲明
extern const char* xls_getVersion(void); extern int xls(int debug); // Set debug. Force library to load? extern void xls_set_formula_hander(xls_formula_handler handler); extern void xls_parseWorkBook(xlsWorkBook* pWB); extern void xls_parseWorkSheet(xlsWorkSheet* pWS); extern xlsWorkBook* xls_open(const char *file,const char *charset); // convert 16bit strings within the spread sheet to this 8-bit encoding (UTF-8 default) #define xls_close xls_close_WB // historical extern void xls_close_WB(xlsWorkBook* pWB); // preferred name extern xlsWorkSheet * xls_getWorkSheet(xlsWorkBook* pWB,int num); extern void xls_close_WS(xlsWorkSheet* pWS); extern xlsSummaryInfo *xls_summaryInfo(xlsWorkBook* pWB); extern void xls_close_summaryInfo(xlsSummaryInfo *pSI); // utility function xlsRow *xls_row(xlsWorkSheet* pWS, WORD cellRow); xlsCell *xls_cell(xlsWorkSheet* pWS, WORD cellRow, WORD cellCol);
但是在libxls.def文件及xls.c文件中卻發現還有寫Excel的函數
EXPORTS brdb @1 DATA dumpbuf @2 get_string @3 ole2_bufread @4 ole2_close @5 ole2_fclose @6 ole2_fopen @7 ole2_open @8 ole2_read @9 ole2_seek @10 ole2_sopen @11 unicode_decode @12 utf8_decode @13 verbose @14 xls @15 xlsConvertBiff @16 xlsConvertBof @17 xlsConvertBoundsheet @18 xlsConvertCol @19 xlsConvertColinfo @20 xlsConvertDouble @21 xlsConvertFont @22 xlsConvertFormat @23 xlsConvertFormula @24 xlsConvertFormulaArray @25 xlsConvertHeader @26 xlsConvertMergedcells @27 xlsConvertPss @28 xlsConvertRow @29 xlsConvertSst @30 xlsConvertWindow @31 xlsConvertXf5 @32 xlsConvertXf8 @33 xlsIntVal @34 xlsShortVal @35 xls_addCell @36 xls_addColinfo @37 xls_addFont @38 xls_addFormat @39 xls_addRow @40 xls_addSST @41 xls_addSheet @42 xls_addXF5 @43 xls_addXF8 @44 xls_appendSST @45 xls_cell @46 xls_close_WB @47 xls_close_WS @48 xls_close_summaryInfo @49 xls_debug @50 DATA xls_dumpSummary @51 xls_formatColumn @52 xls_getCSS @53 xls_getColor @54 xls_getVersion @55 xls_getWorkSheet @56 xls_getfcell @57 xls_is_bigendian @58 xls_makeTable @59 xls_mergedCells @60 xls_open @61 xls_parseWorkBook @62 xls_parseWorkSheet @63 xls_preparseWorkSheet @64 xls_row @65 xls_set_formula_hander @66 xls_showBOF @67 xls_showBookInfo @68 xls_showCell @69 xls_showColinfo @70 xls_showFont @71 xls_showFormat @72 xls_showROW @73 xls_showXF @74 xls_summaryInfo @75
猜想一下libxls庫的作者應該也是想把操作Excel相關的接口寫上的吧,可能出於某種原因導致並沒有寫完或者沒有寫好,有時間試試這幾個函數用起來怎么樣。