前段时间匆匆忙忙写的一个小总结,贴出来请大家指点一下,有什么不好的请指点一下,在编程上我基本上是乱模仿出家,没有受过什么系统的培训。
上个周也就是元旦过后的第一个周,匆匆忙忙的为公司客服部做了一个Excel合并软件。主要功能是:对多个Excel文件,按照对应Sheet和其中对应的列进行合并,也就是说合并的文件Sheet数目以及每一个对应Sheet的对应列名必须相同,如果不相同则不合并。由于时间紧迫,并且上班期间公司不能上外网,害得我只能晚上回家搜集资料,白天在公司再仔细研究,通过查找资料,发现很多人是对Excel中的每一个元素进行处理的,并且有现成的代码可用,我也就用这种方法进行处理了。具体方法是对每一个Excel文件中的每一个Sheet中的每一个元素进行拷贝。由于合并时间比较长,我采用创建一个线程显示进度条并进行合并处理的方法。
主要代码如下:
/*===========================================================================
函 数 名: FileCvtThread
功能描述: 文件合并线程
输入参数: CProgressDlg *pThisObj 进度条的指针
输出参数: None
返回值 : void
创建日期: 2008-1-5
修改日期:
作 者: zcd
附加说明: 文件合并过程中,同时进行进度条位置的控制。
-----------------------------------------------------------------------
历史:
修改时间 修改人 修改内容
2008-1-5 zcd 创建该函数
========================================================================*/
void CProgressDlg::FileCvtThread(CProgressDlg *pThisObj)
{
//设置初始化时进度条的位置及文本
pThisObj->m_progress.SetPos(pThisObj->m_pro);
pThisObj->m_progress.SetText(pThisObj->m_strContent);
//初始化COM控件
if (CoInitialize(NULL)!=0)
{
AfxMessageBox("初始化COM支持库失败!");
exit(1);
}
//声明目的文件用到变量
_Application app;
Workbooks books;
_Workbook book;
Worksheets sheets;
_Worksheet sheet;
Range range;
Range iCell;
LPDISPATCH lpDisp;
COleVariant vResult;
COleVariant
covTrue((short)TRUE),
covFalse((short)FALSE),
covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
//创建Excel 2000服务器(启动Excel)
if(!app.CreateDispatch("Excel.Application"))
{
AfxMessageBox("无法启动Excel服务器!");
return;
}
app.SetVisible(FALSE); //使Excel可见
app.SetUserControl(TRUE); //允许其它用户控制Excel
//打开目的文件
books.AttachDispatch(app.GetWorkbooks());
//声明源文件用到的变量
LPDISPATCH lpDispSour;
_Workbook bookSour;
Worksheets sheetsSour;
_Worksheet sheetSour;
Range rangeSour;
Range iCellSour;
//*****
//打开目的文件
lpDisp = books.Open(pThisObj->m_strDest,
covOptional, covOptional, covOptional, covOptional, covOptional,
covOptional, covOptional, covOptional, covOptional, covOptional,
covOptional, covOptional );
//*****
//得到Workbook
book.AttachDispatch(lpDisp);
//*****
//得到Worksheets
sheets.AttachDispatch(book.GetWorksheets());
//得到一个文件中有几个Sheet
long items = sheets.GetCount();
//*****
//得到当前活跃sheet
//如果有单元格正处于编辑状态中,此操作不能返回,会一直等待
lpDisp=book.GetActiveSheet();
//得到几个源文件
int count = static_cast<int>(pThisObj->m_strArrSour.GetCount());
for (int i = 0; i < count;i++)
{
//打开源文件
lpDispSour = books.Open(pThisObj->m_strArrSour[i].GetString(),
covOptional, covOptional, covOptional, covOptional, covOptional,
covOptional, covOptional, covOptional, covOptional, covOptional,
covOptional, covOptional );
//得到Workbook
bookSour.AttachDispatch(lpDispSour);
//*****
//得到Worksheets
sheetsSour.AttachDispatch(bookSour.GetWorksheets());
//*****
//*****
//得到当前活跃sheet
//如果有单元格正处于编辑状态中,此操作不能返回,会一直等待
lpDispSour=bookSour.GetActiveSheet();
//对每张表做循环拷贝
do
{
//设置开始合并时进度条的位置及文本
pThisObj->m_progress.SetPos(pThisObj->m_pro);
CString strout;
strout.Format("正在合并文件:%s,总共已完成%d%%",pThisObj->m_strArrName[i].GetString(),pThisObj->pro);//
pThisObj->m_progress.SetText(strout);
//得到目的文件的Worksheets
sheet.AttachDispatch(lpDisp);
//*****
//读取已经使用区域的信息,包括已经使用的行数、列数、起始行、起始列
Range usedRange;
usedRange.AttachDispatch(sheet.GetUsedRange());
range.AttachDispatch(usedRange.GetRows());
long iRowNum=range.GetCount(); //已经使用的行数
range.AttachDispatch(usedRange.GetColumns());
long iColNum=range.GetCount(); //已经使用的列数
//得到源Excel文件的Worksheets
sheetSour.AttachDispatch(lpDispSour);
//*****
//读取已经使用区域的信息,包括已经使用的行数、列数、起始行、起始列
Range usedRangeSour;
usedRangeSour.AttachDispatch(sheetSour.GetUsedRange());
rangeSour.AttachDispatch(usedRangeSour.GetRows());
long iRowNumSour=rangeSour.GetCount(); //已经使用的行数
rangeSour.AttachDispatch(usedRangeSour.GetColumns());
long iColNumSour=rangeSour.GetCount(); //已经使用的列数
//判断目的文件与源文件的列数是否相同
if (iColNum != iColNumSour)
{
char buffer[200];
sprintf(buffer,(const char*)"源文件与目的文件在表: %s 中的列数不同",sheet.GetName());
AfxMessageBox(buffer);
return;
}
//获取目的Range
range.AttachDispatch(sheet.GetCells());
//*****
//获取源Range
rangeSour.AttachDispatch(sheetSour.GetCells());
//判断每一列的列名称是否相同,不相同则返回
for (long j = 2; j <= iColNumSour; j++)
{
iCell.AttachDispatch((range.GetItem(COleVariant(long(2)), COleVariant(long(j)))).pdispVal);
vResult = iCell.GetText();
CString str;
if(vResult.vt == VT_BSTR) //字符串
{
str=vResult.bstrVal;
}
else if (vResult.vt==VT_R8) //8字节的数字
{
str.Format("%f",vResult.dblVal);
}
else if(vResult.vt==VT_DATE) //时间格式
{
//SYSTEMTIME st;
//VariantTimeToSystemTime(&vResult.date, &st);
}
else if(vResult.vt==VT_EMPTY) //单元格空的
{
str="";
}
iCellSour.AttachDispatch((rangeSour.GetItem(COleVariant(long(2)), COleVariant(long(j)))).pdispVal);
vResult = iCellSour.GetText();
CString strSour;
if(vResult.vt == VT_BSTR) //字符串
{
strSour=vResult.bstrVal;
}
else if (vResult.vt==VT_R8) //8字节的数字
{
strSour.Format("%f",vResult.dblVal);
}
else if(vResult.vt==VT_DATE) //时间格式
{
//SYSTEMTIME st;
//VariantTimeToSystemTime(&vResult.date, &st);
}
else if(vResult.vt==VT_EMPTY) //单元格空的
{
strSour="";
}
if (str.Compare(strSour) != 0)
{
char buffer[200];
sprintf(buffer,(const char*)"源文件与目的文件在表: %s 中的列项:%s不同",sheet.GetName(),str);
AfxMessageBox(buffer);
return;
}
}
//对每一个位置进行拷贝
for (long i = 2; i <= iRowNumSour; i++)
{
for (long j = 1; j <= iColNumSour; j++)
{
iCellSour.AttachDispatch((rangeSour.GetItem(COleVariant(long(i)), COleVariant(long(j)))).pdispVal);
vResult = iCellSour.GetText();
CString strSour;
if(vResult.vt == VT_BSTR) //字符串
{
strSour=vResult.bstrVal;
}
else if (vResult.vt==VT_R8) //8字节的数字
{
strSour.Format("%f",vResult.dblVal);
}
else if(vResult.vt==VT_DATE) //时间格式
{
//SYSTEMTIME st;
//VariantTimeToSystemTime(&vResult.date, &st);
}
else if(vResult.vt==VT_EMPTY) //单元格空的
{
strSour="";
}
//insert into destination excel
range.SetItem(COleVariant((long)(iRowNum + i - 1)),COleVariant((long)(j)),COleVariant(strSour));
}
}
//设置进度条的位置大小
pThisObj->m_pro += static_cast<int>((double)(100/(items * count)));
//处理下一Sheet
lpDispSour = sheetSour.GetNext();
lpDisp = sheet.GetNext();
} while(lpDispSour != NULL && lpDisp != NULL);
book.Save();
book.Close(covOptional,COleVariant(pThisObj->m_strDest),covOptional);
lpDisp = books.Open(pThisObj->m_strDest,
covOptional, covOptional, covOptional, covOptional, covOptional,
covOptional, covOptional, covOptional, covOptional, covOptional,
covOptional, covOptional );
//*****
//得到Workbook
book.AttachDispatch(lpDisp);
//books.
//*****
//得到Worksheets
sheets.AttachDispatch(book.GetWorksheets());
//*****
//得到当前活跃sheet
//如果有单元格正处于编辑状态中,此操作不能返回,会一直等待
lpDisp=book.GetActiveSheet();
}
book.Save();
//sour
rangeSour.DetachDispatch();
rangeSour.ReleaseDispatch();
sheetSour.DetachDispatch();
sheetSour.ReleaseDispatch();
sheetsSour.DetachDispatch();
sheetsSour.ReleaseDispatch();
bookSour.DetachDispatch();
bookSour.ReleaseDispatch();
//dest
range.DetachDispatch();
range.ReleaseDispatch();
sheet.DetachDispatch();
sheet.ReleaseDispatch();
sheets.DetachDispatch();
sheets.ReleaseDispatch();
book.Close(covOptional,COleVariant(pThisObj->m_strDest),covOptional);
book.DetachDispatch();
book.ReleaseDispatch();
//*****
//关闭所有的book,退出Excel
//book.
books.Close();
books.DetachDispatch();
books.ReleaseDispatch();
delete books;
books = NULL;
app.Quit();
app.DetachDispatch();
app.ReleaseDispatch();
delete app;
app = NULL;
pThisObj->m_progress.SetPos(100);
pThisObj->m_progress.SetText("合并完成");
Sleep(500);//为了使用户看到已合并完成的界面
pThisObj->EndPro(); //调用CDialog::OnOK();关闭对话框。
}
/*===========================================================================
函 数 名: ~CProgressDlg
功能描述: 析构函数
输入参数: None
输出参数: None
返回值 : Void
创建日期: 2008-1-5
修改日期:
作 者: zcd
附加说明:
-----------------------------------------------------------------------
历史:
修改时间 修改人 修改内容
2008-1-5 zcd 创建该函数
========================================================================*/
CProgressDlg::~CProgressDlg()
{
//释放线程句柄
if (m_hFileCvtThreadHandle)
{
CloseHandle(m_hFileCvtThreadHandle);
m_hFileCvtThreadHandle = NULL;
}
//释放COM控件
::CoUninitialize();
AfxMessageBox("数据合并完毕!",MB_ICONINFORMATION);
}
PS:非常BS公司不让上外网的做法,如果公司内网有很多资料我也不反对,问题是没有。想查什么资料只能等下班后再查,唉。。。已经习惯了晚上10点以后到家的日子。。。