作者 Yap Chun Wei 2002年发布 CSpreadSheet 类,采用 ODBC 方式,必须依赖于 Office 是否安装;2006年 发布 BasicExcel类,直接解析 Excel 格式
翻译来源:https://www.codeproject.com/Articles/13852/BasicExcel-A-Class-to-Read-and-Write-to-Microsoft
介绍
4年多前,2001年12月,我发布了CSpreadSheet,它能够读写Microsoft Excel。那个类比较受欢迎。然而,它有一些缺陷,如标题行的必要性,无法读取单元格作为数字等。这些都是依赖于ODBC驱动程序的结果。对ODBC驱动程序的依赖也意味着该类在Unix / Linux环境中不可用。
因此,大概在3年前,我想替换CSpreadSheet
一个可以读取和写入本机Excel格式的类。这将允许该类在Windows以外的环境中使用。它还将使用户能够将数字和字符串读取和写入电子表格。但是,由于Excel文件被保存为复合文件,这并不容易。因此,我必须先写一个类来读写复合文件,我已经完成了。(当我有时间正确地记录该类并为其编写文章时,将会被发布)。同时,该类实际上包含在这个包中)。在我写了类来读写复合文件之后,我开始使用从OpenOffice项目获得的Excel文件格式的信息来写入类来读写Excel文件。唉,
上周,我的工作承诺缓解了,我突然想起了我在3年前写的Excel课程。我想完成这个项目,但是我认为3年后,肯定有人已经完成了类似的项目。所以我在SourgeForge上快速搜索了。令我失望的是,没有这样的项目!所以我决定继续这个项目。我很快看了我的未完成的代码来熟悉自己,并开始写作。现在终于完成了,我向你呈现BasicExcel
。
在我们深入研究之前,我们来BasicExcel
看看它的局限性。这是BasicExcel
一个理由。
- 它不支持格式化
- 它不支持公式
- 它不支持图表
- 它不支持Unicode UTF-32
- 它不支持...
其实它不支持Excel的很多奇特的功能。它是一个基本的类,用于读写简单的东西,如数字和字符串到电子表格。所以也许最好列出它支持的东西。
- 读写数字(整数,实数)和字符串(ANSI,UTF16)
- 添加工作表
- 重命名工作表
- 删除工作表
- 获取工作表的名称
就是这样 正如你所看到的,BasicExcel
真的是基本的,但即使在现在的形式下,它比以前更有能力CSpreadSheet
。然而,虽然它的功能是基本的,但编程并不是基本的。需要大量的代码来读写复合文件,并以原生Excel格式进行读写。因此,总线数BasicExcel
超过6000。
使用代码
我应该列出你应该知道使用的三个类的功能BasicExcel
。接下来是一个示例代码。
BasicExcel类
void New(int sheets=3) | 创建一个包含给定数量的电子表格(最少1个)的新Excel工作簿。 |
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工作表的指针。0 如果没有给定名称的Excel工作表返回。 |
BasicExcelWorksheet* GetWorksheet(const wchar_t* name) | 获取指向已提供Unicode名称的Excel工作表的指针。0 如果没有给定名称的Excel工作表返回。 |
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 。0 如果名称为Unicode格式则返回。 |
wchar_t* GetUnicodeSheetName(size_t sheetIndex) | 在给定索引处获取工作表名称。索引从0 。0 如果名称为ANSI格式,则返回。 |
bool GetSheetName(size_t sheetIndex, char* name) | 在给定索引处获取工作表名称。索引从0 。false 如果名称为Unicode格式则返回。 |
bool GetSheetName(size_t sheetIndex, wchar_t* name) | 在给定索引处获取工作表名称。索引从0开始。false 如果名称为ANSI格式,则返回。 |
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名称赋给另一个ANSI名称的Excel工作表。true 如果成功返回,false 否则。 |
bool RenameWorksheet(const wchar_t* from, const wchar_t* to) | 重命名将Unicode名称指定给另一个Unicode名称的Excel工作表。true 如果成功返回,false 否则。 |
BasicExcelWorksheet类
char* GetAnsiSheetName() | 获取当前工作表名称。0 如果名称为Unicode格式则返回。 |
wchar_t* GetUnicodeSheetName() | 获取当前工作表名称。0 如果名称为ANSI格式,则返回。 |
bool GetSheetName(char* name) | 获取当前工作表名称。false 如果名称为Unicode格式则返回。 |
bool GetSheetName(wchar_t* name) | 获取当前工作表名称。false 如果名称为ANSI格式,则返回。 |
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单元格的指针。行和列从...开始0 。0 如果行超过65535或列超过255则返回。 |
bool EraseCell(size_t row, size_t col) | 擦除单元格的内容 行和列从...开始0 。如果行或列超出范围true ,false 则返回。 |
BasicExcelCell类
int Type() const | 获取存储在当前Excel单元格中的值的类型。返回以下枚举之一:UNDEFINED ,INT ,DOUBLE ,STRING ,WSTRING 。 |
bool Get(int& val) const | 获得integer 价值 false 如果单元格不包含,则返回integer 。 |
bool Get(double& val) const | 获得一个double 值 false 如果单元格不包含a则返回double 。 |
bool Get(char* str) const | 获取ANSI字符串。false 如果单元格不包含ANSI,则返回string 。 |
bool Get(wchar_t* str) const | 获取Unicode字符串。false 如果单元格不包含Unicode,则返回string 。 |
size_t GetStringLength() | ANSI或Unicode字符串的返回长度(不包括null 字符)。 |
int GetInteger() const | 获得integer 价值 0 如果单元格不包含,则返回integer 。 |
double GetDouble() const | 获得一个double 值 0 .<code>0 如果单元格不包含a,则返回</ code /> double 。 |
const char* GetString() const | 获取ANSI string 。0 如果单元格不包含ANSI,则返回string 。 |
const wchar_t* GetWString() const | 获取的统一string 。0 如果单元格不包含Unicode,则返回string 。 |
ostream& operator<<(ostream& os, const BasicExcelCell& cell) | 打印单元格输出stream 。如果单元格未定义,则打印空字符。 |
void Set(int val) | 将当前Excel单元格的内容设置为integer 。 |
void Set(double val) | 将当前Excel单元格的内容设置为a 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单元格的内容设置为a 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)