http://www.codeproject.com/cpp/miniexcel.asp(转贴)
1.main()
#include <stdio.h>
#include <stdlib.h>
#include "mexcel.h"
using namespace miniexcel;
#define SAVEPATH "c://temp//a.xls"
//#define SAVEPATH "/home/andy/tmp/a.xls"
int main (int argc, char **args)
{
FILE *f = fopen (SAVEPATH, "wb");
CMiniExcel miniexcel;
miniexcel(0,0) = "Item1:";
miniexcel(1,0) = "Item2:";
miniexcel(2,0) = "Sum = ";
miniexcel(2,0).setBorder(BORDER_LEFT | BORDER_TOP | BORDER_BOTTOM);
miniexcel(2,0).setAlignament(ALIGN_CENTER);
miniexcel(0,1) = 10;
miniexcel(1,1) = 20;
miniexcel(2,1) = (double)miniexcel(0,1) + (double)miniexcel(1,1);
miniexcel(2,1).setBorder(BORDER_RIGHT | BORDER_TOP | BORDER_BOTTOM);
miniexcel.Write(f);
return 0;
}
2.mexcel.cpp
#include "mexcel.h"
#include <string.h>
namespace miniexcel
{
/* Attach the writer to the specified file */
LittleEndianWriter::LittleEndianWriter (FILE * f)
{
m_pFile = f;
}
/* Destructor closes the file itself */
LittleEndianWriter::~LittleEndianWriter ()
{
fclose (m_pFile);
}
/* Write 1 byte in the output */
void LittleEndianWriter::Write1 (char v)
{
fwrite (&v, 1, 1, m_pFile);
}
/* Write 2 bytes in the output (little endian order) */
void LittleEndianWriter::Write2 (int v)
{
Write1 ((v) & 0xff);
Write1 ((v >> 8) & 0xff);
}
/* Write 4 bytes in the output (little endian order) */
void LittleEndianWriter::Write4 (long v)
{
Write2 ((v) & 0xffff);
Write2 ((v >> 16) & 0xffff);
}
/* Write a 4 byte float in the output */
void LittleEndianWriter::WriteFloatIEEE (float v)
{
fwrite (&v, 1, sizeof (v), m_pFile);
}
/* Write a 8 byte double in the output */
void LittleEndianWriter::WriteDoubleIEEE (double v)
{
fwrite (&v, 1, sizeof (v), m_pFile);
}
/* Write a BIFF header for the opcode nRecno of length nRecLen */
void BIFFRecord::Write (LittleEndianWriter * pWriter, int nRecNo, int nRecLen)
{
pWriter->Write2 (nRecNo);
pWriter->Write2 (nRecLen);
}
/* default constructor for our excel attributes */
excelValueAttributes::excelValueAttributes () {
m_nRow = m_nColumn = 0;
m_nAttr1 = m_nAttr2 = m_nAttr3 = 0;
}
/* set the row/column of these values */
excelValueAttributes::excelValueAttributes (int nRow, int nColumn)
{
m_nRow = nRow;
m_nColumn = nColumn;
m_nAttr1 = m_nAttr2 = m_nAttr3 = 0;
}
/* write them to this endian writer */
void excelValueAttributes::Write (LittleEndianWriter * pWriter)
{
pWriter->Write2 (m_nRow);
pWriter->Write2 (m_nColumn);
pWriter->Write1 (m_nAttr1);
pWriter->Write1 (m_nAttr2);
pWriter->Write1 (m_nAttr3);
}
int excelValueAttributes::getRow ()
{
return m_nRow;
}
void excelValueAttributes::setRow (int v)
{
m_nRow = v;
}
int excelValueAttributes::getColumn ()
{
return m_nColumn;
}
void excelValueAttributes::setColumn (int v)
{
m_nColumn = v;
}
void excelValueAttributes::setHidden (bool v)
{
if (v) {
m_nAttr1 |= 0x80;
} else {
m_nAttr1 &= ~0x80;
}
}
bool excelValueAttributes::getHidden ()
{
return (m_nAttr1 & 0x80) != 0;
}
void excelValueAttributes::setLocked (bool v)
{
if (v) {
m_nAttr1 |= 0x40;
} else {
m_nAttr1 &= ~0x40;
}
}
bool excelValueAttributes::getLocked ()
{
return (m_nAttr1 & 0x40) != 0;
}
void excelValueAttributes::setShaded (bool v)
{
if (v) {
m_nAttr3 |= 0x80;
} else {
m_nAttr3 &= ~0x80;
}
}
bool excelValueAttributes::getShaded ()
{
return (m_nAttr3 & 0x80) != 0;
}
void excelValueAttributes::setBorder (int type)
{
m_nAttr3 &= ~0x78; /* clear existing border */
m_nAttr3 |= (type & 0x78); /* set the new border */
}
int excelValueAttributes::getBorder ()
{
return m_nAttr3 & 0x78;
}
void excelValueAttributes::setAlignament (int type)
{
m_nAttr3 &= ~0x07; /* clear previous value */
m_nAttr3 |= type & 0x07;
}
int excelValueAttributes::getAlignament ()
{
return m_nAttr3 & 0x07;
}
void excelValueAttributes::setFontNum (int v)
{
m_nAttr2 &= ~0xE0; /* clear previous value */
m_nAttr2 |= (v & 0x03) << 5; /* set the new value value */
}
int excelValueAttributes::getFontNum ()
{
return (m_nAttr2 >> 5) & 0x03;
}
void excelValueAttributes::setFormatNum (int v)
{
m_nAttr2 &= ~0x3F; /* clear previous value */
m_nAttr2 |= v & 0x3F; /* set the new value value */
}
int excelValueAttributes::getFormatNum ()
{
return m_nAttr2 & 0x3F;
}
/* write a BOF record */
void excelBOF::Write (LittleEndianWriter * pWriter)
{
BIFFRecord::Write (pWriter, OPCODE_BOF, 4);
pWriter->Write2 (m_nVersion);
pWriter->Write2 (m_nType);
}
/* write a number */
void excelNUMBER::Write (LittleEndianWriter * pWriter)
{
BIFFRecord::Write (pWriter, OPCODE_NUMBER, 15);
excelValueAttributes::Write (pWriter);
pWriter->WriteDoubleIEEE (m_nValue);
}
/* write a label */
void excelLABEL::Write (LittleEndianWriter * pWriter)
{
BIFFRecord::Write (pWriter, OPCODE_LABEL, 8 + strlen (m_pchValue));
excelValueAttributes::Write (pWriter);
pWriter->Write1 (strlen (m_pchValue));
for (unsigned i = 0; i < strlen (m_pchValue); i++) {
pWriter->Write1 (m_pchValue[i]);
}
}
void excelEOF::Write (LittleEndianWriter * pWriter)
{
BIFFRecord::Write (pWriter, OPCODE_EOF, 0);
}
ExcelCell::ExcelCell () {
m_pchValue = NULL;
m_nValue = 0;
m_nType = TYPE_NONE;
}
ExcelCell::ExcelCell(const ExcelCell &v){
m_nType = v.m_nType;
if (m_nType == TYPE_STRING){
m_pchValue = strdup (v.m_pchValue);
}else{
m_pchValue = NULL;
}
m_nValue = v.m_nValue;
CopyAttributes(v);
}
ExcelCell::~ExcelCell () {
if (m_pchValue != NULL) {
free (m_pchValue);
}
}
/* Excell cell can contain a double value */
ExcelCell & ExcelCell::operator = (double v) {
m_nType = TYPE_NUMBER;
m_nValue = v;
return *this;
}
ExcelCell::operator double ()
{
return m_nValue;
}
/* Excell cell can also contain a string */
ExcelCell & ExcelCell::operator = (const char *v) {
m_nType = TYPE_STRING;
if (m_pchValue != NULL) {
free (m_pchValue);
}
m_pchValue = strdup (v); /* FIXME: check for NULL */
return *this;
}
ExcelCell::operator const char *()
{
return m_pchValue;
}
void ExcelCell::clear ()
{
if (m_pchValue != NULL) {
free (m_pchValue);
m_pchValue = NULL;
}
m_nType = TYPE_NONE;
}
ExcelCell& ExcelCell::operator=(const ExcelCell &v){
if (m_pchValue != NULL) {
free (m_pchValue);
m_pchValue = NULL;
}
m_nType = v.m_nType;
if (m_nType == TYPE_STRING){
m_pchValue = strdup (v.m_pchValue);
}
m_nValue = v.m_nValue;
CopyAttributes(v);
return *this;
}
void ExcelCell::Write (LittleEndianWriter * pWriter)
{
if (m_nType == TYPE_NONE) {
return; /* Do nothing if we have no actual value */
}
if (m_nType == TYPE_NUMBER) {
excelNUMBER n (m_nValue);
n.CopyAttributes (*this);
n.Write (pWriter);
} else {
//ASSERT: m_nType == TYPE_STRING
excelLABEL n (m_pchValue);
n.CopyAttributes (*this);
n.Write (pWriter);
}
}
ExcelCell & CMiniExcel::operator ()(unsigned row, unsigned column) {
while (m_vvTableValues.size () <= row) {
vector < ExcelCell > v;
m_vvTableValues.push_back (v); /* add any extra rows */
}
while (m_vvTableValues[row].size () <= column) {
ExcelCell v;
m_vvTableValues[row].push_back (v); /* add any extra columns */
}
return m_vvTableValues[row][column];
}
CMiniExcel::CMiniExcel(){
}
CMiniExcel::~CMiniExcel(){
}
void CMiniExcel::Write (FILE * dest)
{
LittleEndianWriter writer (dest);
excelBOF biffBOF (EXCEL_VERSION, TYPE_WORKSHEET); /* begin and end of file */
excelEOF biffEOF;
unsigned row, column;
biffBOF.Write (&writer);
/* first pass, gather all the numbers */
for (row = 0; row < m_vvTableValues.size (); row++) {
for (column = 0; column < m_vvTableValues[row].size (); column++) {
if (m_vvTableValues[row][column].getType () == ExcelCell::TYPE_NUMBER) {
m_vvTableValues[row][column].setRow (row);
m_vvTableValues[row][column].setColumn (column);
m_vvTableValues[row][column].Write (&writer);
}
}
}
/* second pass for the strings */
for (row = 0; row < m_vvTableValues.size (); row++) {
for (column = 0; column < m_vvTableValues[row].size (); column++) {
if (m_vvTableValues[row][column].getType () == ExcelCell::TYPE_STRING) {
m_vvTableValues[row][column].setRow (row);
m_vvTableValues[row][column].setColumn (column);
m_vvTableValues[row][column].Write (&writer);
}
}
}
biffEOF.Write (&writer);
}
}
3.mexcel.h
#ifndef MINI_EXCEL_H_ALREADY_INCLUDED
#define MINI_EXCEL_H_ALREADY_INCLUDED
#include <stdio.h>
#include <vector>
using namespace std; /* so I can write "vector" instead of "std::vector" */
/* The version of excel we currently support */
#define EXCEL_VERSION 2
/* when we write an excel document, we write this type */
#define TYPE_WORKSHEET 0x10
/* many defies for BIFF Opcodes for different types
they also seem to be in the order they appear in an excel document :-)
*/
#define OPCODE_BOF 0x09
#define OPCODE_FILEPASS 0x2F
#define OPCODE_INDEX 0x0B
#define OPCODE_CALCCOUNT 0x0C
#define OPCODE_CALCMODE 0x0D
#define OPCODE_PRECISION 0x0E
#define OPCODE_REFMODE 0x0F
#define OPCODE_DELTA 0x10
#define OPCODE_ITERATION 0x11
#define OPCODE_1904 0x22
#define OPCODE_BACKUP 0x40
#define OPCODE_PRINT_ROW_HEADERS 0x2A
#define OPCODE_PRINT_GRIDLINES 0x2B
#define OPCODE_HORIZONTAL_PAGE_BREAKS 0x1B
#define OPCODE_VERTICAL_PAGE_BREAKS 0x1A
#define OPCODE_DEFAULT_ROW_HEIGHT 0x25
#define OPCODE_FONT 0x31
#define OPCODE_FONT2 0x32
#define OPCODE_HEADER 0x14
#define OPCODE_FOOTER 0x15
#define OPCODE_LEFT_MARGIN 0x26
#define OPCODE_RIGHT_MARGIN 0x27
#define OPCODE_TOP_MARGIN 0x28
#define OPCODE_BOTTOM_MARGIN 0x29
#define OPCODE_COLWIDTH 0x24
#define OPCODE_EXTERNCOUNT 0x16
#define OPCODE_EXTERNSHEET 0x17
#define OPCODE_EXTERNNAME 0x23
#define OPCODE_FORMATCOUNT 0x1F
#define OPCODE_FORMAT 0x1E
#define OPCODE_NAME 0x18
#define OPCODE_DIMENSIONS 0x00
#define OPCODE_COLUMN_DEFAULT 0x20
#define OPCODE_ROW 0x08
#define OPCODE_BLANK 0x01
#define OPCODE_INTEGER 0x02
#define OPCODE_NUMBER 0x03
#define OPCODE_LABEL 0x04
#define OPCODE_BOOLERR 0x05
#define OPCODE_FORMULA 0x06
#define OPCODE_ARRAY 0x21
#define OPCODE_CONTINUE 0x3C
#define OPCODE_STRING 0x07
#define OPCODE_TABLE 0x36
#define OPCODE_TABLE2 0x37
#define OPCODE_PROTECT 0x12
#define OPCODE_WINDOW_PROTECT 0x19
#define OPCODE_PASSWORD 0x13
#define OPCODE_NOTE 0x1C
#define OPCODE_WINDOW1 0x3D
#define OPCODE_WINDOW2 0x3E
#define OPCODE_PANE 0x41
#define OPCODE_SELECTION 0x1D
#define OPCODE_EOF 0x0A
/* Alignament options for a cell */
#define ALIGN_GENERAL 0
#define ALIGN_LEFT 1
#define ALIGN_CENTER 2
#define ALIGN_RIGHT 3
#define ALIGN_FILL 4
#define ALIGN_MULTIPLAN_DEFAULT 7
/* the border values for a cell */
#define BORDER_LEFT 0x08
#define BORDER_RIGHT 0x10
#define BORDER_TOP 0x20
#define BORDER_BOTTOM 0x40
/* We put everything into the miniexcel namespace */
namespace miniexcel
{
/********************************************************
* First, define a writer for our excel files *
********************************************************/
class LittleEndianWriter{
private:
FILE *m_pFile; /* where to write */
public:
/* a little endian file writer out of a file */
LittleEndianWriter(FILE *f);
/* Destructor will close the file. do not close directly */
~LittleEndianWriter();
/* Write 1 byte in the output */
void Write1(char v);
/* Write 2 bytes in the output (little endian order) */
void Write2(int v);
/* Write 4 bytes in the output (little endian order) */
void Write4(long v);
/* Write a 4 byte float in the output */
void WriteFloatIEEE(float v);
/* Write a 8 byte double in the output */
void WriteDoubleIEEE(double v);
};
/********************************************************
* Everything in Excel is a BIFF record.. so define one *
********************************************************/
class BIFFRecord{
protected: /* Not usefull without subclassing ... */
BIFFRecord () {}
virtual ~BIFFRecord () {}
/* Write a BIFF header for the opcode nRecno of length nRecLen */
void Write (LittleEndianWriter *pWriter, int nRecNo, int nRecLen);
public:
/* We should be able to write every type of BIFF records */
virtual void Write (LittleEndianWriter *pWriter) = 0;
};
/* Since every cell has the same attributes, no matter
of the type, we gather the attributes here
*/
class excelValueAttributes{
private:
int m_nRow; /* row of the value */
int m_nColumn; /* column of the value */
/* all cell attributes held in 3 bytes */
char m_nAttr1;
char m_nAttr2;
char m_nAttr3;
public:
excelValueAttributes ();
excelValueAttributes (int nRow,int nColumn);
~excelValueAttributes (){}
/* like operator=, but a method */
void CopyAttributes(excelValueAttributes v){
m_nRow = v.m_nRow;
m_nColumn = v.m_nColumn;
m_nAttr1 = v.m_nAttr1;
m_nAttr2 = v.m_nAttr2;
m_nAttr3 = v.m_nAttr3;
}
/* write them to this endian writer */
void Write (LittleEndianWriter *pWriter);
/* get/set the position of the current item */
int getRow();
void setRow(int v);
int getColumn();
void setColumn(int v);
/* Tons and tons of attributes that can be set or not... */
void setHidden (bool v);
bool getHidden ();
void setLocked (bool v);
bool getLocked ();
void setShaded (bool v);
bool getShaded ();
void setBorder (int type);
int getBorder ();
void setAlignament (int type);
int getAlignament ();
void setFontNum (int v);
int getFontNum ();
void setFormatNum (int v);
int getFormatNum ();
};
/* The BOF record. A must have. */
class excelBOF : public BIFFRecord{
private:
int m_nVersion; /* Version. in our case EXCEL_VERSION */
int m_nType; /* The type, in our case TYPE_WORKSHEET */
public:
excelBOF (int nVer,int nType):m_nVersion(nVer),m_nType(nType){}
~excelBOF(){}
void Write (LittleEndianWriter *pWriter);
};
/* A number - 8 byte IEEE double
*/
class excelNUMBER : public BIFFRecord,public excelValueAttributes{
private:
double m_nValue;
public:
excelNUMBER (){
m_nValue = 0;
}
excelNUMBER (double val){
m_nValue = val;
}
void setValue (double v){
m_nValue = v;
}
double getValue (){
return m_nValue;
}
void Write (LittleEndianWriter *pWriter);
};
/* A label: up to 256 character string
*/
class excelLABEL : public BIFFRecord,public excelValueAttributes{
private:
char m_pchValue[257];
public:
excelLABEL (){
m_pchValue[0] = '/0';
}
excelLABEL (const char *v){
strncpy (m_pchValue, v, sizeof (m_pchValue));
m_pchValue[sizeof(m_pchValue) - 1] = '/0';
}
void setValue (const char *v){
strncpy (m_pchValue, v, sizeof (m_pchValue));
m_pchValue[sizeof(m_pchValue) - 1] = '/0';
}
const char *getValue (){
return m_pchValue;
}
void Write (LittleEndianWriter *pWriter);
};
/* The EOF record. A must have. */
class excelEOF : public BIFFRecord{
public:
excelEOF() {}
~excelEOF() {}
void Write (LittleEndianWriter *pWriter);
};
/* A generic cell. can contain a number, or a string.
used so we can easely manipulate cells in excel
*/
class ExcelCell:public excelValueAttributes{
private:
char *m_pchValue;
double m_nValue;
int m_nType;
public:
ExcelCell ();
ExcelCell (const ExcelCell &v);
~ExcelCell ();
enum{
TYPE_NONE = 0,
TYPE_NUMBER = 1,
TYPE_STRING = 2
};
/* if someone is interested in what i contain */
int getType(){
return m_nType;
}
/* make it point to nothing */
void clear();
/* the copy operator */
ExcelCell& operator=(const ExcelCell &v);
/* Excell cell can contain a double value */
ExcelCell& operator=(double v);
operator double();
/* Excell cell can also contain a string */
ExcelCell& operator=(const char *v);
operator const char *();
void Write (LittleEndianWriter *pWriter);
};
/********************************************************
* Our class. We will use this class to store an Excel *
* Worksheet and write it to a file *
********************************************************/
class CMiniExcel{
private:
vector<vector<ExcelCell> > m_vvTableValues;
public:
CMiniExcel ();
~CMiniExcel ();
/* Access the columns in the excel document */
ExcelCell &operator() (unsigned row,unsigned column);
/* Write into a file. dest must be opened in "wb" mode.
the file will be closed by this function
*/
void Write (FILE *dest);
};
};
#endif /* #ifndef MINI_EXCEL_H_ALREADY_INCLUDED */