C++操作excel

http://blog.sina.com.cn/s/blog_6163bdeb0102dxcy.html

最近要做MFC操作Excel,發現有篇博文介紹VS2008操作Excel的各種方法,不錯,收藏了。

原文:http://blog.csdn.net/davidhsing/article/details/4231592

 

這些天做個軟件,需要讀取 Excel 並導入到數據庫中,所以研究了一下在 VC 下操作 Excel 的方法,這裏做個總結,以作備忘。

 

一、最常用的 OLE 自動化方式

這個方式應該說是功能最全的方式,可能也是應用的最多的方式。由於這種方式採用的是隱藏啓動 Office Excel 的方式,所以幾乎是全能,任何功能都可以完成。不過缺點也是比較明顯的:

1、採用 OLE 方式,需要用戶計算機上安裝有 Office Excel,否則就失敗;

2、由於是隱藏啓動 Office Excel,而 Mcirosoft 的一貫作風就是功能強大、體積巨大無比,所以這個速度是個很大的瓶頸,如果是批量讀取的話,那...

3、它的基本方法是使用導出 .h 進行 OLE 操作,但是網上關於 Excel OLE 的完善的參考資料並不是很多,大多也是抄來抄去,所以要想很好的使用它們,恐怕還要好好的探索一下。

不過總之,這種方式在文件數目不多,對功能要求大過速度的話,這是首選。

代碼可參考:http://blog.csdn.net/hyz_9257/archive/2008/12/27/3621309.aspx

(一個更好的參考代碼見http://www.cppblog.com/greatws/archive/2008/09/21/62423.html

 

二、ADO/ODBC 的方式

這種方式需要確保 ODBC 中已安裝有 Excel 表格文件的驅動 "MICROSOFT EXCEL DRIVER (*.XLS)",所以同樣依賴於 Office Excel 是否安裝。

常規例子:http://www.vckbase.com/document/viewdoc/?id=421

這裏不得不提的是:新加坡人 Yap Chun Wei 在 CodeProject 上 2001 年發佈的 CSpreadSheet,非常流行的一個 Excel 操作類。地址是:http://www.codeproject.com/KB/database/cspreadsheet.aspx

具體我在最後第六點來介紹和對比。

 

 

三、Sourceforge 上的開源 Excel 庫

搜索了一下,有幾個似乎人氣比較高,像 libXLS,XLSlib 等,下載下來看了一下說明,好像更多是作爲 php 的插件來使用的,對 C++ 似乎沒多大幫助。

 

 

四、第三方收費 Excel 操作庫

第三方收費的,找到一個 LibXL (注意不是 LibXLS),他的官方網站是 http://www.libxl.com/,首先嚐試找了一下 cr,可惜沒有,由於工期緊,我甚至都考慮要付費購買一份授權,$199 啊!在決定之前,還是先好好測試一下他的功能是否達到我的要求,於是編譯了他的幾個 Demo,居然... 他自己的 Edit Demo 居然連自己 Generate Demo 程序生成的 Excel 都打不開,俺機器可是安裝的有 Office Excel 的呀!實在是,寒

 

 

五、一些不需要依賴 Office Excel 的方式

網上還有一些說的不依賴 Office Excel 的方式,比如 http://www.vckbase.com/document/viewdoc/?id=815,但,說實話,這裏的只是理論可行,離實際運用還有很遠的路需要走。

 

 

六、重點推薦的

噹噹噹當,BasicExcel !

他的作者和 CSpreadSheet 的作者是同一個,不過是因爲他考慮到以前 CSpreadSheet 的一些侷限性和想實現兼容性,重新寫的。地址是:http://www.codeproject.com/KB/office/BasicExcel.aspx

 

(這個貌似很不錯,速度快,操作也還方便,就是不太兼容Unicode,後面原文作者提到,他修改了原代碼,可以消除警告,兼容Unicode。demo運行結果如下

image 

demo的代碼在最後給出,以示參考 )

 

對比 CSpreadSheet,他的優點在於:

1、CSpreadSheet 採用 CStringArray 賦值和取值,所以對數字等都處理不是很合適;

2、CSpreadSheet  採用 ODBC 方式,ODBC 是拿來當數據庫讀取和賦值的,所以,必須依賴於 Office 是否安裝;ODBC 的速度也是一大瓶頸;而 BasicExcel 直接解析 Excel 格式,從文件下手,速度有相當提高,並且不再依賴於 Office 是否安裝;

3、CSpreadSheet 不支持對 Sheet 的操作,而 BasicExcel 可以;

4、CSpreadSheet 需要被讀取的 Excel 每一列需要一個列頭,比如“姓名”、“年齡”等,不是 Excel 自身的 A、B、AA 等,沒辦法,要作爲 ODBC 數據源使用,需要相當於數據庫表的列名一樣,這是不可避免的;

...

 

衆多優點,是 CSpreadSheet 不能比的,所以作者在 2006 年新發布了這個類。

我的起點,便在這裏。

 

由於作者在發佈這一款操作類的時候,考慮的更多是跨平臺性,Windows/(*)nix,所以採用的都是標準 C++ 函數,如 wcstombs、wcscpy 等,而這些在 Visual Studio 在被認爲是不安全的,Microsoft 認爲存在緩衝區溢出的隱患,所以 Microsoft 建立了一系列自己的函數,加了個 _s,如 wcstombs_s 等,另外由於不同的平臺對 int short 等的精度不一樣,所以還會有“初始化截斷常量”這樣怪異的警告。總共編譯下來居然有 200 多個 warnning,要崩潰了!於是一個一個修改,終於到最後消滅了所有的 warnning。

另外一個我做的很大的調整就是完善對 Unicode 的支持。原類中作者似乎並沒有考慮到這些,或者說是考慮的不全(誰叫人家新加坡的官方語言是英語呢?),所以只要打開或者保存的文件中含有中文,必定失敗,被這個問題折騰了好久,一點點修改、調試。增加了很多 wchar_t* 形式的重載函數。

對這些類的收集、分析和 Basci Excel 的修改和調試,整整用了我 5 天時間!不過好在,到昨天凌晨,終於大功告成了,可以完美的支持 Unicode 了,嘿嘿

 

 

BasicExcel的demo示例:

#include "BasicExcel.hpp"
#include <stdlib.h>
using namespace YExcel;

int main(int argc, char* argv[])
{
    BasicExcel e;

    // Load a workbook with one sheet, display its contents and save into another file.
    e.Load("example1.xls");   
    BasicExcelWorksheet* sheet1 = e.GetWorksheet("Sheet1");
    if (sheet1)
    {
        size_t maxRows = sheet1->GetTotalRows();
        size_t maxCols = sheet1->GetTotalCols();
        cout << "Dimension of " << sheet1->GetAnsiSheetName() << " (" << maxRows << ", " << maxCols << ")" << endl;

        printf("          ");
        for (size_t c=0; c<maxCols; ++c) printf("d", c+1);
        cout << endl;

        for (size_t r=0; r<maxRows; ++r)
        {
            printf("d", r+1);
            for (size_t c=0; c<maxCols; ++c)
            {
                BasicExcelCell* cell = sheet1->Cell(r,c);
                switch (cell->Type())
                {
                    case BasicExcelCell::UNDEFINED:
                        printf("          ");
                        break;

                    case BasicExcelCell::INT:
                        printf("d", cell->GetInteger());
                        break;

                    case BasicExcelCell::DOUBLE:
                        printf(".6lf", cell->GetDouble());
                        break;

                    case BasicExcelCell::STRING:
                        printf("s", cell->GetString());
                        break;

                    case BasicExcelCell::WSTRING:
                        wprintf(L"s", cell->GetWString());
                        break;
                }
            }
            cout << endl;
        }
    }
    cout << endl;
    e.SaveAs("example2.xls");

    // Create a new workbook with 2 worksheets and write some contents.
    e.New(2);
    e.RenameWorksheet("Sheet1", "Test1");
    BasicExcelWorksheet* sheet = e.GetWorksheet("Test1");
    BasicExcelCell* cell;
    if (sheet)
    {
        for (size_t c=0; c<4; ++c)
        {
            cell = sheet->Cell(0,c);
            cell->Set((int)c);
        }

        cell = sheet->Cell(1,3);
        cell->SetDouble(3.141592654);

        sheet->Cell(1,4)->SetString("Test str1");
        sheet->Cell(2,0)->SetString("Test str2");
        sheet->Cell(2,5)->SetString("Test str1");

        sheet->Cell(4,0)->SetDouble(1.1);
        sheet->Cell(4,1)->SetDouble(2.2);
        sheet->Cell(4,2)->SetDouble(3.3);
        sheet->Cell(4,3)->SetDouble(4.4);
        sheet->Cell(4,4)->SetDouble(5.5);

        sheet->Cell(4,4)->EraseContents();
    }

    sheet = e.AddWorksheet("Test2", 1);
    sheet = e.GetWorksheet(1);
    if (sheet)
    {
        sheet->Cell(1,1)->SetDouble(1.1);
        sheet->Cell(2,2)->SetDouble(2.2);
        sheet->Cell(3,3)->SetDouble(3.3);
        sheet->Cell(4,4)->SetDouble(4.4);
        sheet->Cell(70,2)->SetDouble(5.5);
    }
    e.SaveAs("example3.xls");

    // Load the newly created sheet and display its contents
    e.Load("example3.xls");

    size_t maxSheets = e.GetTotalWorkSheets();
    cout << "Total number of worksheets: " << e.GetTotalWorkSheets() << endl;
    for (size_t i=0; i<maxSheets; ++i)
    {
        BasicExcelWorksheet* sheet = e.GetWorksheet(i);
        if (sheet)
        {
            size_t maxRows = sheet->GetTotalRows();
            size_t maxCols = sheet->GetTotalCols();
            cout << "Dimension of " << sheet->GetAnsiSheetName() << " (" << maxRows << ", " << maxCols << ")" << endl;

            if (maxRows>0)
            {
                printf("          ");
                for (size_t c=0; c<maxCols; ++c) printf("d", c+1);
                cout << endl;
            }

            for (size_t r=0; r<maxRows; ++r)
            {
                printf("d", r+1);
                for (size_t c=0; c<maxCols; ++c)
                {
                    cout << setw(10) << *(sheet->Cell(r,c));    // Another way of printing a cell content.               
                }
                cout << endl;
            }
            if (i==0)
            {
                ofstream f("example4.csv");
                sheet->Print(f, ',', '\"');    // Save the first sheet as a CSV file.
                f.close();
            }
        }
        cout << endl;
    }

    system("pause");
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章