/**************************************************************************************/
/* */
/* XLSRW相关说明 */
/* */
/* wxy3064one##163.com 2009.11.18 Version:1.0 */
/**************************************************************************************/
(一) 功能介绍
XLSRW.dll是读取EXCEL5.0及其以上版本EXCEL文件的COM库
能正确读取中文。无需OFFICE环境,效率高。
目前最新版本是1.0.0.3 ,暂未实现写功能.
(二) 版本历史
v1.0.0.0:
wxy 2009.11.17 ~ 2009.11.18: 将EXCEL文件格式用com的方式进行了封装,实现了读取功能.
v1.0.0.1:
wxy 2009.12.9: 1.修改了FormatNumber函数,使之能够准确地显示EXCEL的浮点数,精度最高8位.
2.增加了日期的显示支持.
v1.0.0.2:
wxy 2009.12.16:1.增加了EXCEL 2007(XLSX)的读取
v1.0.0.3:
wxy 2010.6.28: 1.修正了读取XLSX时 的死循环问题, 主要是读取每个sheet时,某些参数需重新置0
2.修正了读取XLSX时最后一行数据读不到的情况
(三) 发布方法
1.XLSRW.dll,ICSharpCode.SharpZipLib.dll放在一起.
2.执行Init.exe.
(四) 使用方法
(1) XLSRW接口说明如下:
[Guid("63B7592C-45FB-4895-B0DD-E83348E99176")]
public interface XLSRW_Interface
{
[DispId(1)]
/*
函数名 : InitXLSRW
参数 :
功能 : 初始化XLSRW环境
*/
void InitXLSRW();
[DispId(2)]
/*
函数名 : ReleaseXLSRW
参数 :
功能 : 释放XLSRW环境
*/
void ReleaseXLSRW();
[DispId(3)]
/*
函数名 : OpenXLS
参数 : _xlsfile EXCEL文件名
功能 : 打开指定的EXCEL文件
返回值 : 成功EXCEL文件的句柄,失败为-1
*/
int OpenXLS(string _xlsfile);
[DispId(4)]
/*
函数名 : CloseXLS
参数 : _xlshandle EXCEL文件句柄
功能 : 关闭EXCEL文件
*/
void CloseXLS(int _xlshandle);
/************************EXCEL文件读取*****************************/
[DispId(5)]
/*
函数名 : GetWorksheetByName
参数 : _xlshandle EXCEL文件句柄 ,_sheetname Sheet名字
功能 : 在当前EXCEL中打开对应的Sheet
返回值 : 成功返回true,否则为false
*/
bool GetWorksheetByName(int _xlshandle,string _sheetname);
[DispId(6)]
/*
函数名 : GetWorksheetByIndex
参数 : _xlshandle EXCEL文件句柄 , _sheetindex Sheet序号,从0开始
功能 : 在当前EXCEL中打开对应的Sheet
返回值 : 成功返回true,否则为false
*/
bool GetWorksheetByIndex(int _xlshandle, int _sheetindex);
[DispId(7)]
/*
函数名 : getSheetTotalRows
参数 :
功能 : 得到当前Sheet的行数
*/
int getSheetTotalRows();
[DispId(8)]
/*
函数名 : getSheetTotalCols
参数 :
功能 : 得到当前Sheet的列数
*/
int getSheetTotalCols();
[DispId(9)]
/*
函数名 : getCellStr
参数 : row 行(从0开始) col 列(从0开始)
功能 : 在当前Sheet中读取对应行列的值
*/
string getCellStr(int row,int col);
/**************************************************************************/
[DispId(10)]
/*
函数名 : getLastErrMsg
参数 :
功能 : 返回打开EXCEL时的错误
*/
string getLastErrMsg();
[DispId(11)]
/*
函数名 : GetTotalWorkSheets
参数 : _xlshandle EXCEL文件句柄
功能 : 得到当前EXCEL的Sheet个数
*/
int GetTotalWorkSheets(int _xlshandle);
[DispId(12)]
/*
函数名 : getSheetName
参数 : _xlshandle EXCEL文件句柄 , _sheetindex Sheet序号,从0开始
功能 : 得到sheet的名字
*/
string getSheetName(int _xlshandle,int _sheetindex);
[DispId(13)]
/*
函数名 : try_convert_datetime
参数 : value 浮点数
功能 : 将value转成日期
*/
string try_convert_datetime(double value);
[DispId(14)]
/*
函数名 : format_number
参数 : value 字符串
功能 : 将value转换成精度为nbits的浮点数,且以字符串输出
*/
string format_number(string value,int nbits);
}
(2)调用方法: 通过调用COM对象来实现,下面给出VC和BCB下读取EXCEL的调用方法.
$1 VC中的使用
Example:
第一步: 在文件头中加入 #import "XLSRW.tlb"
第二步: 调用方法:
CFileDialog dlg(TRUE, "xls;xlsx", "",OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,"Excel File(*.xls;*.xlsx)");
if (dlg.DoModal() == IDOK)
{
HRESULT hr;
CoInitialize(NULL);
//创建XLSRW接口类实例
XLSRW::XLSRW_InterfacePtr ptr;
hr = ptr.CreateInstance(__uuidof(XLSRW::XLSRW_Class));
if(hr == S_OK)
{
//初始化XLSRW环境
ptr->InitXLSRW();
BSTR bstrText = dlg.GetFileName().AllocSysString();
//打开EXCEL文件
int ret = ptr->OpenXLS(bstrText);
if (ret >0)
{
//打开第一个sheet
if (ptr->GetWorksheetByIndex(ret,0))
{
//得到行,列数.
int maxRows = ptr->getSheetTotalRows() - 1;//通常第一行是标题行
int maxCols = ptr->getSheetTotalCols();
CString s;
s.Format("(行:%d ,列: %d) ,下面显示前两行的数据",maxRows,maxCols - 1);
AfxMessageBox(s);
for (int r=0; r<2/*maxRows*/; ++r)
{
for (int c=1; c<=maxCols; ++c)
{
s = (LPCTSTR)ptr->getCellStr(r,c-1);
//获取每个单元格的数据
if (r >0)
{
if (c != 10)
AfxMessageBox(s);
else
AfxMessageBox(ptr->try_convert_datetime(atof(s)));//将第10列按日期格式输出
}else
AfxMessageBox(s);
}
}
}else AfxMessageBox(ptr->getLastErrMsg());
//关闭EXCEL
ptr->CloseXLS(ret);
}else AfxMessageBox(ptr->getLastErrMsg());
SysFreeString(bstrText); // 用完释放
//释放XLSRW环境
ptr->ReleaseXLSRW();
}
CoUninitialize();
}
$2 BCB中的使用
Example:
//第一步: 在工程中加入 XLSRW.tlb文件,以便生成对应的 XLSRW_TLB.h文件
// (会造成类型冲突,解决办法有两种:
// 第一种: 直接使用生成好的XLSRW_TLB.h和XLSRW_TLB.cpp文件
// 第二种: 把生成的XLSRW_TLB.h中 #include "mscorlib_TLB.h" 注释掉,和mscorlib相关的文件都可以不要
// )
//
第二步: 在文件头中加入 #include "XLSRW_TLB.h"
#include <objbase.h> //CoInitialize和CoUninitialize所在的头文件
第三步: 调用方法:
AnsiString xlsFileName;
int maxRows,maxCols;
int h = 0;
::CoInitialize(NULL);
XLSRW_Interface* pUnk = 0;
CoCreateInstance(CLSID_XLSRW_Class, 0, CLSCTX_ALL, __uuidof(XLSRW_Interface), (void**)&pUnk);
pUnk->InitXLSRW();
OpenDialog1->Filter = "MicroSoft Excel files(*.xls;*.xlsx) |*.XLS;*.XLSX" ;
if(OpenDialog1->Execute())
{
xlsFileName = OpenDialog1->FileName;
if (pUnk != 0)
{
h = pUnk->OpenXLS(WideString(xlsFileName).c_bstr());
if (h == -1)
{
StringGrid1->ColCount = 5;
StringGrid1->RowCount = 5;
for (int r=0; r<5; ++r)
{
for (int c=0; c<5; ++c)
{
StringGrid1->Cells[c][r] = "";
}
}
ShowMessage( pUnk->getLastErrMsg());
}else{
//打开 Sheet1
//pUnk->GetWorksheetByName(h,WideString("sheet1").c_bstr())
if (pUnk->GetWorksheetByIndex(h,0))
{
//得到 Sheet1的行列总数
maxRows = pUnk->getSheetTotalRows();
maxCols = pUnk->getSheetTotalCols();
StringGrid1->ColCount = maxCols + 1;
StringGrid1->RowCount = maxRows - 1;
for (int r=0; r<maxRows; ++r)
{
for (int c=0; c<=maxCols; ++c)
{
if (c != 0)
{
StringGrid1->Cells[c][r] = AnsiString(pUnk->getCellStr(r,c-1));
if (r >0)
{
//将第13列按日期格式输出
if (c == 13)
{
try
{
StringGrid1->Cells[c][r] = pUnk->try_convert_datetime(StrToFloat(StringGrid1->Cells[c][r]));
}catch(...)
{
}
}
}
}
else
{
if (r != 0)
StringGrid1->Cells[c][r] = IntToStr(r);
}
}
}
ShowMessage("StringGrid1读取完成! 共读取 行: " + IntToStr(maxRows -1) + ", 列: " + IntToStr(maxCols));
}
pUnk->CloseXLS(h);
}
}
}
pUnk->ReleaseXLSRW();
::CoUninitialize();
(五) 参考文档
(1) MicroSoft的<MICROSOFT OFFICE EXCEL 97-2007 BINARY FILE FORMAT SPECIFICATION> PDF
(2) MicroSoft的<Windows Compound Binary File Format Specification> PDF
(3) OpenOffice.org的<Microsoft Compound Doucument File Format> PDF 2007 Revison 1.5
(4) OpenOffice.org的<Microsoft Excel File Format> PDF 2005 Revision 1.39
(六) 下载
下载地址: http://download.csdn.net/source/3137514
(七) 未完成的功能
1. 支持EXCEL的写功能
2. 支持图像的读取和写入
3. 某些不能读取的EXCEL文件的重新解读
(八) 开源
情况许可的条件下,我会考虑将代码开源
v1.0.0.3 版本的开源代码下载地址(无需积分):http://download.csdn.net/source/3386509
感兴趣的网友可以下载下来再上面增加新的功能。
2011年6月22日