网上有很多C++利用OLE读取Excel的例子,其中有提到利用COleSafeArray类来预加载数据来提升效率,但是没有实现快速的写入大量数据到Excel,今天专门写了一个方法,同样利用COleSafeArray类将大量数据一次性的写入Excel,提高了效率,参考代码如下:
void CExcelFile::SetString(long startRow, long startCol, long RowCount, long 
ColCount, vector< vector<CComBSTR> >& writeData)
 {
     if (startRow < 1 || startCol < 1)
     {
         return;
     }
    VARTYPE vt = VT_BSTR; /*数组元素的类型,string*/
     SAFEARRAYBOUND sabWrite[2]; /*用于定义数组的维数和下标的起始值*/
     sabWrite[0].cElements = RowCount;
     sabWrite[0].lLbound = 0;
     sabWrite[1].cElements = ColCount;
     sabWrite[1].lLbound = 0;
    COleSafeArray olesaWrite;
     olesaWrite.Create(vt, sizeof(sabWrite) / sizeof(SAFEARRAYBOUND), 
sabWrite);
     /*通过指向数组的指针来对二维数组的元素进行间接赋值*/
     long(*pArray)[2] = NULL;
     olesaWrite.AccessData((void **)&pArray);
     memset(pArray, 0, sabWrite[0].cElements * sabWrite[1].cElements * 
sizeof(long));
     /*释放指向数组的指针*/
     olesaWrite.UnaccessData();
     pArray = NULL;
    /*对二维数组的元素进行逐个赋值*/
     long index[2] = { 0, 0 };
     long lFirstLBound = 0;
     long lFirstUBound = 0;
     long lSecondLBound = 0;
     long lSecondUBound = 0;
     olesaWrite.GetLBound(1, &lFirstLBound);
     olesaWrite.GetUBound(1, &lFirstUBound);
     olesaWrite.GetLBound(2, &lSecondLBound);
     olesaWrite.GetUBound(2, &lSecondUBound);
     for (long i = lFirstLBound; i <= lFirstUBound; i++)
     {
         index[0] = i;
         for (long j = lSecondLBound; j <= lSecondUBound; j++)
         {
             index[1] = j;
             
             //防止越界而且不写入空值
             if ((i < writeData.size()) && (j < writeData[i].size()) && 
(writeData[i][j].Length() != 0))
             {
                 olesaWrite.PutElement(index, (void*)writeData[i][j]);
             }
         }
     }
     
     CString strStartRow;
     CString strStartCol;
     strStartRow.Format(_T("%d"), startRow);
     strStartCol = ConvertNumColtoStringCol(startCol);
     CString strRange1;
     strRange1 = strStartCol + strStartRow;
     
     CString strEndRow;
     CString strEndCol;
     strEndRow.Format(_T("%d"), startRow + RowCount - 1);
     strEndCol = ConvertNumColtoStringCol(startCol + ColCount - 1);
     CString strRange2;
     strRange2 = strEndCol + strEndRow;
     ///
     CRange start_range = excel_work_sheet_.get_Range(COleVariant(strRange1), 
COleVariant(strRange2));
     start_range.put_Value2((VARIANT)olesaWrite);
     start_range.ReleaseDispatch();
 }
//将Excel数字列转为字符串列,1--A
 CString CExcelFile::ConvertNumColtoStringCol(long Col)
 {
     CString strBack;
     do {
         Col--;
         int n = Col % 26;
         CString strTemp;
         strTemp.Format(_T("%c"), n + (int) 'A');
         strBack += strTemp;
         Col = (int)((Col - n) / 26);
     } while (Col > 0);
     return strBack;
 }
需要注意的地方是,字符串必须要要BSTR类型,不然会提示内存不足,我这里用的是CComBSTR。