BasicExcel - 用于读写 Microsoft Excel 的类






4.94/5 (189投票s)
2006年4月20日
10分钟阅读

5686067

66178
用于读写 Microsoft Excel 的类
引言
早在 4 年多前,即 2001 年 12 月,我发布了 CSpreadSheet,该类能够读写 Microsoft Excel。那个类相对比较受欢迎。然而,它存在一些不足之处,例如需要标题行,无法将单元格读取为数字等。所有这些都是由于它依赖于 ODBC 驱动程序。对 ODBC 驱动程序的依赖也意味着该类无法在 Unix/Linux 环境中使用。
因此,大约在 3 年前,我想用一个能够以原生 Excel 格式读写文件的类来替换 CSpreadSheet
。这将允许该类在 Windows 以外的环境中使用。它还将使用户能够读写电子表格中的数字和字符串。然而,这不是一项容易的任务,因为 Excel 文件保存为复合文件。因此,我必须先编写一个读写复合文件的类,我已经完成了。 (当我有时间好好记录这个类并为其撰写文章时,它将稍后发布。同时,该类实际上已包含在此软件包中。)在我编写完读写复合文件的类之后,我开始使用从 OpenOffice 项目获得的 Excel 文件格式信息来编写读写 Excel 文件的类。可惜,工作承诺阻止了我完成这个项目。
上周,我的工作承诺有所缓解,我突然想起了 3 年前我正在编写的 Excel 类。我想完成这个项目,但我认为 3 年后,肯定有人已经做过类似的项目了。于是我在 SourgeForge 上快速搜索了一下。令我沮丧的是,没有任何此类项目!因此,我决定继续这个项目。我快速查看了我未完成的代码以便熟悉,然后开始编写。现在它终于完成了,我向您介绍 BasicExcel
。
在我们深入了解 BasicExcel
之前,让我们看看它的局限性。它被称为 BasicExcel
是有原因的。
- 它不支持格式设置
- 它不支持公式
- 它不支持图表
- 它不支持 Unicode UTF-32
- 它不支持...
实际上,它不支持 Excel 的许多花哨功能。它旨在成为一个基本的类,用于读写电子表格中的简单内容,例如数字和字符串。所以也许最好列出它支持的功能。
- 读写数字(整数、实数)和字符串(ANSI、UTF16)
- 添加工作表
- 重命名工作表
- 删除工作表
- 获取工作表名称
就这些了。如您所见,BasicExcel
确实非常基础,但即使在其当前形式下,它也比 CSpreadSheet
强大得多。然而,尽管它的功能基础,但编程它并不基础。读写复合文件,以及以原生 Excel 格式读写都需要大量的代码。因此,BasicExcel
的总行数超过 6000 行。
使用代码
我应该列出您需要了解的三个类中的函数,以便使用 BasicExcel
。之后将提供示例代码。
class BasicExcel
void New(int sheets=3) |
创建一个新的 Excel 工作簿,其中包含指定数量的工作表(最少 1 个)。 |
bool Load(const char* filename) |
从文件加载 Excel 工作簿。 |
bool Save() |
将当前 Excel 工作簿保存到已打开的文件。 |
bool SaveAs(const char* filename) |
将当前 Excel 工作簿另存为文件。 |
size_t GetTotalWorkSheets() |
当前 Excel 工作簿中 Excel 工作表的总数。 |
BasicExcelWorksheet* GetWorksheet(size_t sheetIndex) |
获取指定索引处的 Excel 工作表的指针。索引从 0 开始。如果索引无效,则返回 0 。 |
BasicExcelWorksheet* GetWorksheet(const char* name) |
获取具有给定 ANSI 名称的 Excel 工作表的指针。如果不存在具有给定名称的 Excel 工作表,则返回 0 。 |
BasicExcelWorksheet* GetWorksheet(const wchar_t* name) |
获取具有给定 Unicode 名称的 Excel 工作表的指针。如果不存在具有给定名称的 Excel 工作表,则返回 0 。 |
BasicExcelWorksheet* AddWorksheet(int sheetIndex=-1) |
在指定索引处添加一个新的 Excel 工作表。给工作表起的名称是 SheetX,其中 X 是一个从 1 开始的数字。索引从 0 开始。如果 sheetIndex == -1 ,则工作表将添加到最后一个位置。成功则返回工作表指针,否则返回 0 。 |
BasicExcelWorksheet* AddWorksheet(const char* name, int sheetIndex=-1) |
在指定索引处添加一个具有给定 ANSI 名称的新 Excel 工作表。索引从 0 开始。如果 sheetIndex == -1 ,则工作表将添加到最后一个位置。成功则返回工作表指针,否则返回 0。 |
BasicExcelWorksheet* AddWorksheet(const wchar_t* name, int sheetIndex=-1) |
在指定索引处添加一个具有给定 Unicode 名称的新 Excel 工作表。索引从 0 开始。如果 sheetIndex == -1 ,则工作表将添加到最后一个位置。成功则返回工作表指针,否则返回 0。 |
bool DeleteWorksheet(size_t sheetIndex) |
删除指定索引处的 Excel 工作表。索引从 0 开始。成功则返回 true ,否则返回 false 。 |
bool DeleteWorksheet(const char* name) |
删除具有给定 ANSI 名称的 Excel 工作表。成功则返回 true ,否则返回 false 。 |
bool DeleteWorksheet(const wchar_t* name) |
删除具有给定 Unicode 名称的 Excel 工作表。成功则返回 true ,否则返回 false 。 |
char* GetAnsiSheetName(size_t sheetIndex) |
获取指定索引处的工作表名称。索引从 0 开始。如果名称是 Unicode 格式,则返回 0 。 |
wchar_t* GetUnicodeSheetName(size_t sheetIndex) |
获取指定索引处的工作表名称。索引从 0 开始。如果名称是 ANSI 格式,则返回 0 。 |
bool GetSheetName(size_t sheetIndex, char* name) |
获取指定索引处的工作表名称。索引从 0 开始。如果名称是 Unicode 格式,则返回 false 。 |
bool GetSheetName(size_t sheetIndex, wchar_t* name) |
获取指定索引处的工作表名称。索引从 0 开始。如果名称是 ANSI 格式,则返回 false 。 |
bool RenameWorksheet(size_t sheetIndex, const char* to) |
将指定索引处的 Excel 工作表重命名为给定的 ANSI 名称。索引从 0 开始。成功则返回 true ,否则返回 false 。 |
bool RenameWorksheet(size_t sheetIndex, const wchar_t* to) |
将指定索引处的 Excel 工作表重命名为给定的 Unicode 名称。索引从 0 开始。成功则返回 true ,否则返回 false 。 |
bool RenameWorksheet(const char* from, const char* to) |
将具有给定 ANSI 名称的 Excel 工作表重命名为另一个 ANSI 名称。成功则返回 true ,否则返回 false 。 |
bool RenameWorksheet(const wchar_t* from, const wchar_t* to) |
将具有给定 Unicode 名称的 Excel 工作表重命名为另一个 Unicode 名称。成功则返回 true ,否则返回 false 。 |
class BasicExcelWorksheet
char* GetAnsiSheetName() |
获取当前工作表的名称。如果名称是 Unicode 格式,则返回 0 。 |
wchar_t* GetUnicodeSheetName() |
获取当前工作表的名称。如果名称是 ANSI 格式,则返回 0 。 |
bool GetSheetName(char* name) |
获取当前工作表的名称。如果名称是 Unicode 格式,则返回 false 。 |
bool GetSheetName(wchar_t* name) |
获取当前工作表的名称。如果名称是 ANSI 格式,则返回 false 。 |
bool Rename(const char* to) |
将当前 Excel 工作表重命名为另一个 ANSI 名称。成功则返回 true ,否则返回 false 。 |
bool Rename(const wchar_t* to) |
将当前 Excel 工作表重命名为另一个 Unicode 名称。成功则返回 true ,否则返回 false 。 |
void Print(ostream& os, char delimiter=',', char textQualifier='\0') |
将整个工作表打印到输出流,使用定义的定界符分隔每个列,并使用定义的 textQualifier 包围文本。如果不希望使用任何文本限定符,则省略 textQualifier 参数。 |
size_t GetTotalRows() |
当前 Excel 工作表中的总行数。 |
size_t GetTotalCols() |
当前 Excel 工作表中的总列数。 |
BasicExcelCell* Cell(size_t row, size_t col) |
返回一个 Excel 单元格的指针。row 和 col 从 0 开始。如果 row 超过 65535 或 col 超过 255,则返回 0 。 |
bool EraseCell(size_t row, size_t col) |
擦除单元格内容。row 和 col 从 0 开始。成功则返回 true ,如果 row 或 col 超过范围,则返回 false 。 |
class BasicExcelCell
int Type() const |
获取当前 Excel 单元格中存储的值的类型。返回以下枚举之一:UNDEFINED 、INT 、DOUBLE 、STRING 、WSTRING 。 |
bool Get(int& val) const |
获取一个 integer 值。如果单元格不包含 integer ,则返回 false 。 |
bool Get(double& val) const |
获取一个 double 值。如果单元格不包含 double ,则返回 false 。 |
bool Get(char* str) const |
获取一个 ANSI 字符串。如果单元格不包含 ANSI string ,则返回 false 。 |
bool Get(wchar_t* str) const |
获取一个 Unicode 字符串。如果单元格不包含 Unicode string ,则返回 false 。 |
size_t GetStringLength() |
返回 ANSI 或 Unicode 字符串的长度(不包括 null 字符)。 |
int GetInteger() const |
获取一个 integer 值。如果单元格不包含 integer ,则返回 0 。 |
double GetDouble() const |
获取一个 double 值。如果单元格不包含 double ,则返回 0 .<code>0 。 |
const char* GetString() const |
获取一个 ANSI string 。如果单元格不包含 ANSI string ,则返回 0 。 |
const wchar_t* GetWString() const |
获取一个 Unicode string 。如果单元格不包含 Unicode string ,则返回 0 。 |
ostream& operator<<(ostream& os, const BasicExcelCell& cell) |
将单元格打印到输出 stream 。如果单元格未定义,则打印一个 null 字符。 |
void Set(int val) |
将当前 Excel 单元格的内容设置为 integer 。 |
void Set(double val) |
将当前 Excel 单元格的内容设置为 double 。 |
void Set(const char* str) |
将当前 Excel 单元格的内容设置为 ANSI string 。 |
void Set(const wchar_t* str) |
将当前 Excel 单元格的内容设置为 Unicode strin g。 |
void SetInteger(int val) |
将当前 Excel 单元格的内容设置为 integer 。 |
void SetDouble(double val) |
将当前 Excel 单元格的内容设置为 double 。 |
void SetString(const char* str) |
将当前 Excel 单元格的内容设置为 ANSI string 。 |
void SetWString(const wchar_t* str) |
将当前 Excel 单元格的内容设置为 Unicode string 。 |
void EraseContents() |
擦除当前 Excel 单元格的内容。将类型设置为 UNDEFINED 。 |
#include "BasicExcel.hpp"
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("%10d", c+1);
cout << endl;
for (size_t r=0; r<maxRows; ++r)
{
printf("%10d", 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("%10d", cell->GetInteger());
break;
case BasicExcelCell::DOUBLE:
printf("%10.6lf", cell->GetDouble());
break;
case BasicExcelCell::STRING:
printf("%10s", cell->GetString());
break;
case BasicExcelCell::WSTRING:
wprintf(L"%10s", 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("%10d", c+1);
cout << endl;
}
for (size_t r=0; r<maxRows; ++r)
{
printf("%10d", 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;
}
return 0;
}
参考文献
- OpenOffice 的 Excel 文件格式 (http://sc.openoffice.org/excelfileformat.pdf)
历史
- 2006 年 4 月 20 日:发布版本 1。
- 2006 年 4 月 22 日:发布版本 1.1。修复了复合文件无法写入超过 65535 字节文件的问题。修复了读写包含大量字符串的 Excel 文件的问题。
- 2006 年 4 月 30 日:发布版本 1.2。添加了 operator<< 以将
BasicExcelCell
传递给输出流。向BasicExcelWorksheet
添加了Print()
以将工作表打印到输出流。将BasicExcelWorksheet
函数RenameWorkSheet()
重命名为Rename()
。将BasicExcelCell
的Get
函数更改为const
函数。 - 2006 年 5 月 10 日:发布版本 1.3。修复了读取包含亚洲字符的 Excel 文件的问题。
- 2006 年 5 月 13 日:发布版本 1.4。修复了读写包含大量字符串的 Excel 文件的问题。
- 2006 年 5 月 15 日:发布版本 1.5。删除了
ExtSST
的代码,因为它导致了读写包含大量字符串的 Excel 文件的问题。 - 2006 年 5 月 16 日:发布版本 1.6。优化了读写代码。
- 2006 年 5 月 22 日:发布版本 1.7。修复了用于消除一些警告的代码。修复了
BasicExcelWorksheet::Cell
的错误。修复了BasicExcel::UpdateWorksheets()
的错误。 - 2006 年 5 月 23 日:发布版本 1.8。修复了读取包含大量 Unicode 字符串的 Excel 文件的问题。修复了用于消除一些警告的代码。修复了
BoolErr
中的变量code_
重复问题。对BasicExcelCell:Set
函数进行了少量修改。 - 2006 年 5 月 24 日:发布版本 1.9。将
Style
中的name_
从SmallString
更改为LargeString
。修复了BasicExcelCell::GetString
和BasicExcelCell::GetWString
中的错误。对BasicExcel
和BasicExcelWorksheet
中检查 unicode 的函数进行了少量修改。对SmallString::Read
进行了少量修改。 - 2006 年 5 月 30 日:发布版本 1.10。修复了读取包含大量字符串的 Excel 文件的问题。消除了内存泄漏。为 VC6 用户添加了 BasicExcelVC6.hpp 和 BasicExcelVC6.cpp。
- 2006 年 6 月 2 日:发布版本 1.11。修复了读写包含大量 Unicode 和 ANSI 字符串的 Excel 文件的问题。
- 2006 年 6 月 6 日:发布版本 1.12。修复了读写包含大量 Unicode 和 ANSI 字符串的 Excel 文件的问题。
- 2006 年 8 月 1 日:发布版本 1.13。更改了
BasicExcelCell::Get()
,使其在必要时将存储的double
作为integer
获取,反之亦然。更改了BasicExcelCell::Get()
,使其不会在字符串为空时产生任何错误。更改了BasicExcelCell::SetString()
和BasicExcelCell::SetWString()
,使其不会保存空字符串。 - 2006 年 8 月 6 日:发布版本 1.14。修复了读取包含
null
字符串的 Excel 文件的问题。
最终注释
如果您在任何程序中使用此类,无论是商业、共享软件、免费软件、开源软件等,我都非常感谢您能给我发一封电子邮件让我知道。得知我的类对某人有用,我会很高兴。