VC中操作EXCEL文件

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 */

你可能感兴趣的:(String,Excel,border,output,attributes,destructor)