1395 lines
30 KiB
C++
1395 lines
30 KiB
C++
/////////////////////////////////////////////////////////////////////////
|
||
// 类名:CSpreadSheet
|
||
// 功能:读、写Excel文件或指定分隔符分隔的文本文件类
|
||
// 附注:导入、导出指定数据的Excel文件或分隔符文本文件
|
||
// 修改:徐景周(jingzhou_xu@163.com)
|
||
// 组织:Future Studio
|
||
// 日期:2003.1.8
|
||
////////////////////////////////////////////////////////////////////////
|
||
#ifndef CSPREADSHEET_H
|
||
#define CSPREADSHEET_H
|
||
|
||
#include <odbcinst.h>
|
||
#include <afxdb.h>
|
||
|
||
class CSpreadSheet
|
||
{
|
||
public:
|
||
CSpreadSheet(CString File, CString SheetOrSeparator, bool Backup = false); // 为进行读写操作,进行的预处理工作
|
||
~CSpreadSheet(); // 清理工作
|
||
void Close();
|
||
|
||
bool AddHeaders(CStringArray &FieldNames, bool replace = false); // 添加首行列头
|
||
bool DeleteSheet(); // 删除分隔符文本文件内容
|
||
bool DeleteSheet(CString SheetName); // 删除指定表格全部内容,但表格自身不被删除
|
||
bool AddRow(CStringArray &RowValues, long row = 0, bool replace = false); // 播放或替换一行
|
||
bool AddCell(CString CellValue, CString column, long row = 0, bool Auto = true); // 使用行号或字母列号替换或添加一单元格
|
||
bool AddCell(CString CellValue, short column, long row = 0); // 使用行、列号替换或添加一单元格
|
||
bool ReplaceRows(CStringArray &NewRowValues, CStringArray &OldRowValues); // 在Excel表格中替换行
|
||
bool ReadRow(CStringArray &RowValues, long row = 0); // 读取一行
|
||
bool ReadColumn(CStringArray &ColumnValues, CString column, bool Auto = true); // 使用行号、字母列号读取一列
|
||
bool ReadColumn(CStringArray &ColumnValues, short column); // 使用列号读取一列
|
||
bool ReadCell (CString &CellValue, CString column, long row = 0, bool Auto = true); // 使用行号、字母列号读取单元格
|
||
bool ReadCell (CString &CellValue, short column, long row = 0); // 使用列号读取单元格
|
||
void BeginTransaction(); // 开始事务
|
||
bool Commit(); // 保存改变状态
|
||
bool RollBack(); // 回滚改变状态
|
||
bool Convert(CString SheetOrSeparator);
|
||
// 获取首行列头名
|
||
inline void GetFieldNames (CStringArray &FieldNames) {FieldNames.RemoveAll(); FieldNames.Copy(m_aFieldNames);}
|
||
inline long GetTotalRows() {return m_dTotalRows;} // 获取总行数
|
||
inline short GetTotalColumns() {return m_dTotalColumns;} // 获取总列数
|
||
inline long GetCurrentRow() {return m_dCurrentRow;} // 获取当前选中行
|
||
inline bool GetBackupStatus() {return m_bBackup;} // 获取备份状态. True表示备份, False不进行备份
|
||
inline bool GetTransactionStatus() {return m_bTransaction;} // 获取事务状态. True表示开始, False表示没有开始或开始时产生错误
|
||
inline CString GetLastError() {return m_sLastError;} // 获取最后错误信息
|
||
|
||
private:
|
||
bool Open(); // 为进行读写打开处理
|
||
void GetExcelDriver(); // 获取Excel-ODBC驱动程序
|
||
short CalculateColumnNumber(CString column, bool Auto); // 转换Excel字母列号为对应数字列号
|
||
|
||
bool m_bAppend; // 新建表格还是使用原表格内部标志
|
||
bool m_bBackup; // 备份状态内部标志
|
||
bool m_bExcel; // 是Excel表格文件还是分隔符文本文件内部标志
|
||
bool m_bTransaction; // 事务状态内部标志
|
||
|
||
long m_dCurrentRow; // 当前行号索引, 起始为1
|
||
long m_dTotalRows; // 总行数
|
||
short m_dTotalColumns; // Excel文件时总列数,分隔符文本文件中最大列数
|
||
|
||
CString m_sSql; // 打开Excel进行读写SQL语句
|
||
CString m_sDsn; // 打开Excel进行读写的DSN名
|
||
CString m_stempSql; // 临时SQL字符串
|
||
CString m_stempString; // 临时字符串
|
||
CString m_sSheetName; // Excel表格名
|
||
CString m_sExcelDriver; // Excel驱动程序名
|
||
CString m_sFile; // 文件名
|
||
CString m_sSeparator; // 文本文件分隔符
|
||
CString m_sLastError; // 错误信息
|
||
|
||
CStringArray m_atempArray; // 临时数组
|
||
CStringArray m_aFieldNames; // 字段数组
|
||
CStringArray m_aRows; // 行存储
|
||
|
||
CDatabase *m_Database; // 数据库变量
|
||
CRecordset *m_rSheet; // 记录集变量
|
||
};
|
||
|
||
// 为读写进行打开处理(File -- 文件名,SheetOrSeparator -- Excel表名或文本分隔符,Backup -- 是否创建备份表)
|
||
CSpreadSheet::CSpreadSheet(CString File, CString SheetOrSeparator, bool Backup /* = false */) :
|
||
m_Database(NULL), m_rSheet(NULL), m_sFile(File),
|
||
m_dTotalRows(0), m_dTotalColumns(0), m_dCurrentRow(1),
|
||
m_bAppend(false), m_bBackup(Backup), m_bTransaction(false)
|
||
{
|
||
// 检测文件是Excel表格还是分隔符文本文件
|
||
m_stempString = m_sFile.Right(4);
|
||
m_stempString.MakeLower();
|
||
if (m_stempString == ".xls") // 当是Excel表格文件时
|
||
{
|
||
m_bExcel = true;
|
||
m_sSheetName = SheetOrSeparator;
|
||
m_sSeparator = " ,;.?";
|
||
}
|
||
else // 当是分隔符文本文件时
|
||
{
|
||
m_bExcel = false;
|
||
m_sSeparator = SheetOrSeparator;
|
||
}
|
||
|
||
// 当文件是Excel文件时
|
||
if (m_bExcel)
|
||
{
|
||
m_Database = new CDatabase;
|
||
GetExcelDriver();
|
||
m_sDsn.Format("DRIVER={%s};DSN='';FIRSTROWHASNAMES=1;READONLY=FALSE;CREATE_DB=\"%s\";DBQ=%s", m_sExcelDriver, m_sFile, m_sFile);
|
||
|
||
if (Open()) // 是否已存在Excel文件及表可以打开
|
||
{
|
||
if (m_bBackup) // Excel中表存在并可以打开的话,是否做原始备份表
|
||
{
|
||
if ((m_bBackup) && (m_bAppend))
|
||
{
|
||
CString tempSheetName = m_sSheetName;
|
||
m_sSheetName = m_sSheetName + "备份";
|
||
m_bAppend = false;
|
||
|
||
// 在此创建备份表
|
||
if (!Commit())
|
||
{
|
||
m_bBackup = false;
|
||
}
|
||
m_bAppend = true;
|
||
m_sSheetName = tempSheetName;
|
||
m_dCurrentRow = 1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else // 当文件是指定分隔符分隔的文本文件时
|
||
{
|
||
if (Open())
|
||
{
|
||
if ((m_bBackup) && (m_bAppend))
|
||
{
|
||
m_stempString = m_sFile;
|
||
m_stempSql.Format("%s.bak", m_sFile);
|
||
m_sFile = m_stempSql;
|
||
if (!Commit())
|
||
{
|
||
m_bBackup = false;
|
||
}
|
||
m_sFile = m_stempString;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 清理工作
|
||
CSpreadSheet::~CSpreadSheet()
|
||
{
|
||
Close();
|
||
}
|
||
// 清理工作
|
||
void CSpreadSheet::Close()
|
||
{
|
||
if ( NULL != m_rSheet )
|
||
{
|
||
m_rSheet->Close();
|
||
delete m_rSheet;
|
||
m_rSheet = NULL;
|
||
}
|
||
if (NULL != m_Database)
|
||
{
|
||
m_Database->Close();
|
||
delete m_Database;
|
||
m_Database=NULL;
|
||
}
|
||
}
|
||
// 添加首行列头到表格中
|
||
bool CSpreadSheet::AddHeaders(CStringArray &FieldNames, bool replace)
|
||
{
|
||
if (m_bAppend) // 原表格后追加
|
||
{
|
||
if (replace) // 替换首行而不是添加新列
|
||
{
|
||
if (!AddRow(FieldNames, 1, true))
|
||
{
|
||
return false;
|
||
}
|
||
else
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
|
||
if (ReadRow(m_atempArray, 1)) // 添加新列
|
||
{
|
||
if (m_bExcel)
|
||
{
|
||
// 检查首行列头字段是否重复
|
||
for (int i = 0; i < FieldNames.GetSize(); i++)
|
||
{
|
||
for (int j = 0; j < m_atempArray.GetSize(); j++)
|
||
{
|
||
if (FieldNames.GetAt(i) == m_atempArray.GetAt(j))
|
||
{
|
||
m_sLastError.Format("首行列头字段重复:%s\n", FieldNames.GetAt(i));
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
m_atempArray.Append(FieldNames);
|
||
if (!AddRow(m_atempArray, 1, true))
|
||
{
|
||
m_sLastError = "添加列头时产生错误\n";
|
||
return false;
|
||
}
|
||
|
||
// 更新总列数
|
||
if (m_atempArray.GetSize() > m_dTotalColumns)
|
||
{
|
||
m_dTotalColumns = m_atempArray.GetSize();
|
||
}
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
else // 新表格
|
||
{
|
||
m_dTotalColumns = FieldNames.GetSize();
|
||
if (!AddRow(FieldNames, 1, true))
|
||
{
|
||
return false;
|
||
}
|
||
else
|
||
{
|
||
m_dTotalRows = 1;
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 删除分隔符文本文件内容
|
||
bool CSpreadSheet::DeleteSheet()
|
||
{
|
||
if (m_bExcel)
|
||
{
|
||
if (DeleteSheet(m_sSheetName))
|
||
{
|
||
return true;
|
||
}
|
||
else
|
||
{
|
||
m_sLastError = "删除表格时产生错误\n";
|
||
return false;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
m_aRows.RemoveAll();
|
||
m_aFieldNames.RemoveAll();
|
||
m_dTotalColumns = 0;
|
||
m_dTotalRows = 0;
|
||
if (!m_bTransaction)
|
||
{
|
||
Commit();
|
||
}
|
||
m_bAppend = false; // 设置新表格标志
|
||
|
||
return true;
|
||
}
|
||
}
|
||
|
||
// 删除指定Excel表格内容,表格自身不被删除
|
||
bool CSpreadSheet::DeleteSheet(CString SheetName)
|
||
{
|
||
if (m_bExcel) // 当是Excel表格时
|
||
{
|
||
// 删除表格
|
||
m_Database->OpenEx(m_sDsn, CDatabase::noOdbcDialog);
|
||
SheetName = "[" + SheetName + "$A1:IV65536]";
|
||
m_stempSql.Format ("DROP TABLE %s", SheetName);
|
||
try
|
||
{
|
||
m_Database->ExecuteSQL(m_stempSql);
|
||
m_Database->Close();
|
||
m_aRows.RemoveAll();
|
||
m_aFieldNames.RemoveAll();
|
||
m_dTotalColumns = 0;
|
||
m_dTotalRows = 0;
|
||
}
|
||
catch(CDBException *pEx)
|
||
{
|
||
m_sLastError = pEx->m_strError;
|
||
m_Database->Close();
|
||
pEx->Delete();
|
||
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
else // 当是分隔符文本文件时
|
||
{
|
||
return DeleteSheet();
|
||
}
|
||
}
|
||
|
||
// 播放或替换一行到表格中,默认为添加一新行
|
||
bool CSpreadSheet::AddRow(CStringArray &RowValues, long row, bool replace)
|
||
{
|
||
long tempRow;
|
||
|
||
if (row == 1)
|
||
{
|
||
if (m_bExcel)
|
||
{
|
||
// 检查Excel表格首行列头字段是否重复
|
||
for (int i = 0; i < RowValues.GetSize(); i++)
|
||
{
|
||
for (int j = 0; j < RowValues.GetSize(); j++)
|
||
{
|
||
if ((i != j) && (RowValues.GetAt(i) == RowValues.GetAt(j)))
|
||
{
|
||
m_sLastError.Format("首行列头字段重复:%s\n", RowValues.GetAt(i));
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 检查首行列头数是否减小
|
||
if (RowValues.GetSize() < m_dTotalColumns)
|
||
{
|
||
m_sLastError = "新列头数不能小于原列头数";
|
||
return false;
|
||
}
|
||
m_dTotalColumns = RowValues.GetSize();
|
||
}
|
||
|
||
// 更新首行(列头)
|
||
m_aFieldNames.RemoveAll();
|
||
m_aFieldNames.Copy(RowValues);
|
||
}
|
||
else
|
||
{
|
||
if (m_bExcel)
|
||
{
|
||
if (m_dTotalColumns == 0)
|
||
{
|
||
m_sLastError = "没有列头,首先要加入列头\n";
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (m_bExcel) // Excel表格文件时
|
||
{
|
||
if (RowValues.GetSize() > m_aFieldNames.GetSize())
|
||
{
|
||
m_sLastError = "列数大于表格中总列数\n";
|
||
return false;
|
||
}
|
||
}
|
||
else // 分隔符文本文件时
|
||
{
|
||
// 更新最大列数
|
||
if (RowValues.GetSize() > m_dTotalColumns)
|
||
{
|
||
m_dTotalColumns = RowValues.GetSize();
|
||
}
|
||
}
|
||
|
||
// 转换行值
|
||
m_stempString.Empty();
|
||
for (int i = 0; i < RowValues.GetSize(); i++)
|
||
{
|
||
if (i != RowValues.GetSize()-1) // 不是最后一列
|
||
{
|
||
m_stempSql.Format("\"%s\"%s", RowValues.GetAt(i), m_sSeparator);
|
||
m_stempString += m_stempSql;
|
||
}
|
||
else // 最后一列
|
||
{
|
||
m_stempSql.Format("\"%s\"", RowValues.GetAt(i));
|
||
m_stempString += m_stempSql;
|
||
}
|
||
}
|
||
|
||
if (row)
|
||
{
|
||
if (row <= m_dTotalRows) // 不用添加新行
|
||
{
|
||
if (replace) // 替换行
|
||
{
|
||
m_aRows.SetAt(row-1, m_stempString);
|
||
}
|
||
else // 插入行
|
||
{
|
||
m_aRows.InsertAt(row-1, m_stempString);
|
||
m_dTotalRows++;
|
||
}
|
||
|
||
if (!m_bTransaction)
|
||
{
|
||
Commit();
|
||
}
|
||
return true;
|
||
}
|
||
else // 添加新行
|
||
{
|
||
// 插入空行直到指定行号
|
||
m_dCurrentRow = m_dTotalRows;
|
||
m_stempSql.Empty();
|
||
CString nullString;
|
||
for (int i = 1; i <= m_dTotalColumns; i++)
|
||
{
|
||
if (i != m_dTotalColumns)
|
||
{
|
||
if (m_bExcel)
|
||
{
|
||
nullString.Format("\" \"%s", m_sSeparator);
|
||
}
|
||
else
|
||
{
|
||
nullString.Format("\"\"%s", m_sSeparator);
|
||
}
|
||
m_stempSql += nullString;
|
||
}
|
||
else
|
||
{
|
||
if (m_bExcel)
|
||
{
|
||
m_stempSql += "\" \"";
|
||
}
|
||
else
|
||
{
|
||
m_stempSql += "\"\"";
|
||
}
|
||
}
|
||
}
|
||
for (int j = m_dTotalRows + 1; j < row; j++)
|
||
{
|
||
m_dCurrentRow++;
|
||
m_aRows.Add(m_stempSql);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
tempRow = m_dCurrentRow;
|
||
m_dCurrentRow = m_dTotalRows;
|
||
}
|
||
|
||
// 插入一新行
|
||
m_dCurrentRow++;
|
||
m_aRows.Add(m_stempString);
|
||
|
||
if (row > m_dTotalRows)
|
||
{
|
||
m_dTotalRows = row;
|
||
}
|
||
else if (!row)
|
||
{
|
||
m_dTotalRows = m_dCurrentRow;
|
||
m_dCurrentRow = tempRow;
|
||
}
|
||
if (!m_bTransaction)
|
||
{
|
||
Commit();
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
// 使用行号、字母列号替换或添加一单元格到Excel表格中,默认为添加单元格到一新行中,
|
||
// 如果你想使用字母列号作为列头名可将Auto置为false
|
||
bool CSpreadSheet::AddCell(CString CellValue, CString column, long row, bool Auto)
|
||
{
|
||
short columnIndex = CalculateColumnNumber(column, Auto);
|
||
if (0 == columnIndex)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
if (AddCell(CellValue, columnIndex, row))
|
||
{
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
// 使用数字行号、列号替换或添加一个单元格到表格中,默认为添加单元格到一新行
|
||
bool CSpreadSheet::AddCell(CString CellValue, short column, long row)
|
||
{
|
||
if (0 == column)
|
||
{
|
||
m_sLastError = "列数不能为0\n";
|
||
return false;
|
||
}
|
||
|
||
long tempRow;
|
||
|
||
if (m_bExcel) // 当是Excel表格文件时
|
||
{
|
||
if (column > m_aFieldNames.GetSize() + 1)
|
||
{
|
||
m_sLastError = "指定列号大于表格中存在的总列数\n";
|
||
return false;
|
||
}
|
||
}
|
||
else // 当是分隔符文本文件时
|
||
{
|
||
// 更新最大列数
|
||
if (column > m_dTotalColumns)
|
||
{
|
||
m_dTotalColumns = column;
|
||
}
|
||
}
|
||
|
||
if (row)
|
||
{
|
||
if (row <= m_dTotalRows)
|
||
{
|
||
ReadRow(m_atempArray, row);
|
||
|
||
// 改变指定行
|
||
m_atempArray.SetAtGrow(column-1, CellValue);
|
||
|
||
if (row == 1)
|
||
{
|
||
if (m_bExcel) // 检查列头字段是否重复
|
||
{
|
||
for (int i = 0; i < m_atempArray.GetSize(); i++)
|
||
{
|
||
for (int j = 0; j < m_atempArray.GetSize(); j++)
|
||
{
|
||
if ((i != j) && (m_atempArray.GetAt(i) == m_atempArray.GetAt(j)))
|
||
{
|
||
m_sLastError.Format("首行字段重复(列头):%s\n", m_atempArray.GetAt(i));
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 更新首行(列头)
|
||
m_aFieldNames.RemoveAll();
|
||
m_aFieldNames.Copy(m_atempArray);
|
||
}
|
||
|
||
if (!AddRow(m_atempArray, row, true))
|
||
{
|
||
return false;
|
||
}
|
||
|
||
if (!m_bTransaction)
|
||
{
|
||
Commit();
|
||
}
|
||
return true;
|
||
}
|
||
else
|
||
{
|
||
// 插入空行直到指定行号
|
||
m_dCurrentRow = m_dTotalRows;
|
||
m_stempSql.Empty();
|
||
CString nullString;
|
||
for (int i = 1; i <= m_dTotalColumns; i++)
|
||
{
|
||
if (i != m_dTotalColumns)
|
||
{
|
||
if (m_bExcel)
|
||
{
|
||
nullString.Format("\" \"%s", m_sSeparator);
|
||
}
|
||
else
|
||
{
|
||
nullString.Format("\"\"%s", m_sSeparator);
|
||
}
|
||
m_stempSql += nullString;
|
||
}
|
||
else
|
||
{
|
||
if (m_bExcel)
|
||
{
|
||
m_stempSql += "\" \"";
|
||
}
|
||
else
|
||
{
|
||
m_stempSql += "\"\"";
|
||
}
|
||
}
|
||
}
|
||
for (int j = m_dTotalRows + 1; j < row; j++)
|
||
{
|
||
m_dCurrentRow++;
|
||
m_aRows.Add(m_stempSql);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
tempRow = m_dCurrentRow;
|
||
m_dCurrentRow = m_dTotalRows;
|
||
}
|
||
|
||
// 插入单元格
|
||
m_dCurrentRow++;
|
||
m_stempString.Empty();
|
||
for (int j = 1; j <= m_dTotalColumns; j++)
|
||
{
|
||
if (j != m_dTotalColumns) // 没有最后一列
|
||
{
|
||
if (j != column)
|
||
{
|
||
if (m_bExcel)
|
||
{
|
||
m_stempSql.Format("\" \"%s", m_sSeparator);
|
||
}
|
||
else
|
||
{
|
||
m_stempSql.Format("\"\"%s", m_sSeparator);
|
||
}
|
||
m_stempString += m_stempSql;
|
||
}
|
||
else
|
||
{
|
||
m_stempSql.Format("\"%s\"%s", CellValue, m_sSeparator);
|
||
m_stempString += m_stempSql;
|
||
}
|
||
}
|
||
else // 最后一列
|
||
{
|
||
if (j != column)
|
||
{
|
||
if (m_bExcel)
|
||
{
|
||
m_stempString += "\" \"";
|
||
}
|
||
else
|
||
{
|
||
m_stempString += "\"\"";
|
||
}
|
||
}
|
||
else
|
||
{
|
||
m_stempSql.Format("\"%s\"", CellValue);
|
||
m_stempString += m_stempSql;
|
||
}
|
||
}
|
||
}
|
||
|
||
m_aRows.Add(m_stempString);
|
||
|
||
if (row > m_dTotalRows)
|
||
{
|
||
m_dTotalRows = row;
|
||
}
|
||
else if (!row)
|
||
{
|
||
m_dTotalRows = m_dCurrentRow;
|
||
m_dCurrentRow = tempRow;
|
||
}
|
||
if (!m_bTransaction)
|
||
{
|
||
Commit();
|
||
}
|
||
return true;
|
||
}
|
||
|
||
// 检索和替换Excel表格中行数据
|
||
bool CSpreadSheet::ReplaceRows(CStringArray &NewRowValues, CStringArray &OldRowValues)
|
||
{
|
||
if (m_bExcel) // 当是Excel表格文件时
|
||
{
|
||
// 打开或创建Excel文件
|
||
m_Database->OpenEx(m_sDsn, CDatabase::noOdbcDialog);
|
||
m_stempSql.Format("UPDATE [%s] SET ", m_sSheetName);
|
||
for (int i = 0; i < NewRowValues.GetSize(); i++)
|
||
{
|
||
m_stempString.Format("[%s]='%s', ", m_aFieldNames.GetAt(i), NewRowValues.GetAt(i));
|
||
m_stempSql = m_stempSql + m_stempString;
|
||
}
|
||
m_stempSql.Delete(m_stempSql.GetLength()-2, 2);
|
||
m_stempSql = m_stempSql + " WHERE (";
|
||
for (int j = 0; j < OldRowValues.GetSize()-1; j++)
|
||
{
|
||
m_stempString.Format("[%s]='%s' AND ", m_aFieldNames.GetAt(j), OldRowValues.GetAt(j));
|
||
m_stempSql = m_stempSql + m_stempString;
|
||
}
|
||
m_stempSql.Delete(m_stempSql.GetLength()-4, 5);
|
||
m_stempSql += ")";
|
||
|
||
try
|
||
{
|
||
m_Database->ExecuteSQL(m_stempSql);
|
||
m_Database->Close();
|
||
Open();
|
||
return true;
|
||
}
|
||
catch(CDBException *pEx)
|
||
{
|
||
m_sLastError = pEx->m_strError;
|
||
m_Database->Close();
|
||
pEx->Delete();
|
||
return false;
|
||
}
|
||
}
|
||
else // 当是分隔符的文本文件时
|
||
{
|
||
m_sLastError = "这个涵数对分隔符文本文件无效\n";
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// 读取表格中一行,默认为读取下一行
|
||
bool CSpreadSheet::ReadRow(CStringArray &RowValues, long row)
|
||
{
|
||
// 检查指定行号是否大于表格中总行数
|
||
if (row <= m_aRows.GetSize())
|
||
{
|
||
if (0 != row)
|
||
{
|
||
m_dCurrentRow = row;
|
||
}
|
||
else if (m_dCurrentRow > m_aRows.GetSize())
|
||
{
|
||
return false;
|
||
}
|
||
|
||
// 读取指定行
|
||
RowValues.RemoveAll();
|
||
m_stempString = m_aRows.GetAt(m_dCurrentRow-1);
|
||
m_dCurrentRow++;
|
||
|
||
// 检索分隔行的分隔符
|
||
int separatorPosition;
|
||
m_stempSql.Format("\"%s\"", m_sSeparator);
|
||
separatorPosition = m_stempString.Find(m_stempSql); // 如果分隔符是字符"?"
|
||
if (separatorPosition != -1)
|
||
{
|
||
// 保存列
|
||
int nCount = 0;
|
||
int stringStartingPosition = 0;
|
||
while (separatorPosition != -1)
|
||
{
|
||
nCount = separatorPosition - stringStartingPosition;
|
||
RowValues.Add(m_stempString.Mid(stringStartingPosition, nCount));
|
||
stringStartingPosition = separatorPosition + m_stempSql.GetLength();
|
||
separatorPosition = m_stempString.Find(m_stempSql, stringStartingPosition);
|
||
}
|
||
nCount = m_stempString.GetLength() - stringStartingPosition;
|
||
RowValues.Add(m_stempString.Mid(stringStartingPosition, nCount));
|
||
|
||
// 删除第一列引用符号
|
||
m_stempString = RowValues.GetAt(0);
|
||
m_stempString.Delete(0, 1);
|
||
RowValues.SetAt(0, m_stempString);
|
||
|
||
// 删除最后列引用符号
|
||
m_stempString = RowValues.GetAt(RowValues.GetSize()-1);
|
||
m_stempString.Delete(m_stempString.GetLength()-1, 1);
|
||
RowValues.SetAt(RowValues.GetSize()-1, m_stempString);
|
||
|
||
return true;
|
||
}
|
||
else
|
||
{
|
||
// 保存列
|
||
separatorPosition = m_stempString.Find(m_sSeparator); // 当分隔符是字符"?"
|
||
if (separatorPosition != -1)
|
||
{
|
||
int nCount = 0;
|
||
int stringStartingPosition = 0;
|
||
while (separatorPosition != -1)
|
||
{
|
||
nCount = separatorPosition - stringStartingPosition;
|
||
RowValues.Add(m_stempString.Mid(stringStartingPosition, nCount));
|
||
stringStartingPosition = separatorPosition + m_sSeparator.GetLength();
|
||
separatorPosition = m_stempString.Find(m_sSeparator, stringStartingPosition);
|
||
}
|
||
nCount = m_stempString.GetLength() - stringStartingPosition;
|
||
RowValues.Add(m_stempString.Mid(stringStartingPosition, nCount));
|
||
return true;
|
||
}
|
||
else // 表格只有一列时
|
||
{
|
||
// 如果存在在,删除开始和结束时的引用符号
|
||
int quoteBegPos = m_stempString.Find('\"');
|
||
int quoteEndPos = m_stempString.ReverseFind('\"');
|
||
if ((quoteBegPos == 0) && (quoteEndPos == m_stempString.GetLength()-1))
|
||
{
|
||
m_stempString.Delete(0, 1);
|
||
m_stempString.Delete(m_stempString.GetLength()-1, 1);
|
||
}
|
||
|
||
RowValues.Add(m_stempString);
|
||
}
|
||
}
|
||
}
|
||
|
||
m_sLastError = "指定行大于表格中总行数\n";
|
||
|
||
return false;
|
||
}
|
||
|
||
// 使用字母列号从Excel表格中读取一列,如果想将字母列作为列号的话将Auto置为false
|
||
bool CSpreadSheet::ReadColumn(CStringArray &ColumnValues, CString column, bool Auto)
|
||
{
|
||
short columnIndex = CalculateColumnNumber(column, Auto);
|
||
if (0 == columnIndex)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
if (ReadColumn(ColumnValues, columnIndex))
|
||
{
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
// 使用数字列号从表格中读取一列
|
||
bool CSpreadSheet::ReadColumn(CStringArray &ColumnValues, short column)
|
||
{
|
||
if (0 == column)
|
||
{
|
||
m_sLastError = "列数不能为0\n";
|
||
return false;
|
||
}
|
||
|
||
int tempRow = m_dCurrentRow;
|
||
m_dCurrentRow = 1;
|
||
ColumnValues.RemoveAll();
|
||
for (int i = 1; i <= m_aRows.GetSize(); i++)
|
||
{
|
||
// 读取每一行
|
||
if (ReadRow(m_atempArray, i))
|
||
{
|
||
// 在指定列中获取单元格内容
|
||
if (column <= m_atempArray.GetSize())
|
||
{
|
||
ColumnValues.Add(m_atempArray.GetAt(column-1));
|
||
}
|
||
else
|
||
{
|
||
ColumnValues.Add("");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
m_dCurrentRow = tempRow;
|
||
m_sLastError = "读取行时产生错误\n";
|
||
return false;
|
||
}
|
||
}
|
||
m_dCurrentRow = tempRow;
|
||
return true;
|
||
}
|
||
|
||
// 从Excel表格中使用首行(列头)、字母列号读取单元格内容,默认为在下一行中读取下一个单元格内容
|
||
// 如果你想将字母列作为列头名的话可将Auto置为false
|
||
bool CSpreadSheet::ReadCell (CString &CellValue, CString column, long row, bool Auto)
|
||
{
|
||
short columnIndex = CalculateColumnNumber(column, Auto);
|
||
if (0 == columnIndex)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
if (ReadCell(CellValue, columnIndex, row))
|
||
{
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
// 在表格文件中使用行、列号读取单元格内容,默认(row无效)为下一行中读取下一个单元格
|
||
bool CSpreadSheet::ReadCell (CString &CellValue, short column, long row)
|
||
{
|
||
if (0 == column)
|
||
{
|
||
m_sLastError = "列不能为0\n";
|
||
return false;
|
||
}
|
||
|
||
int tempRow = m_dCurrentRow;
|
||
if (row)
|
||
{
|
||
m_dCurrentRow = row;
|
||
}
|
||
if (ReadRow(m_atempArray, m_dCurrentRow))
|
||
{
|
||
// 获取指定列中单元格数据
|
||
if (column <= m_atempArray.GetSize())
|
||
{
|
||
CellValue = m_atempArray.GetAt(column-1);
|
||
}
|
||
else
|
||
{
|
||
CellValue.Empty();
|
||
m_dCurrentRow = tempRow;
|
||
return false;
|
||
}
|
||
m_dCurrentRow = tempRow;
|
||
return true;
|
||
}
|
||
m_dCurrentRow = tempRow;
|
||
m_sLastError = "读取行时产生错误\n";
|
||
|
||
return false;
|
||
}
|
||
|
||
// 事务开始
|
||
void CSpreadSheet::BeginTransaction()
|
||
{
|
||
m_bTransaction = true;
|
||
}
|
||
|
||
// 提交改变的数据到表格或文本文件中,在此创建Excel中表
|
||
bool CSpreadSheet::Commit()
|
||
{
|
||
if (m_bExcel) // 当是Excel表格文件时
|
||
{
|
||
// 打开或创建Excel文件
|
||
m_Database->OpenEx(m_sDsn, CDatabase::noOdbcDialog);
|
||
|
||
if (m_bAppend)
|
||
{
|
||
// 如果已经存在表格,则删除它
|
||
m_stempString= "[" + m_sSheetName + "$A1:IV65536]";
|
||
m_stempSql.Format ("DROP TABLE %s", m_stempString);
|
||
try
|
||
{
|
||
m_Database->ExecuteSQL(m_stempSql);
|
||
}
|
||
catch(CDBException *pEx)
|
||
{
|
||
m_sLastError = pEx->m_strError;
|
||
m_Database->Close();
|
||
pEx->Delete();
|
||
return false;
|
||
}
|
||
|
||
// 创建一个新的表格
|
||
m_stempSql.Format("CREATE TABLE [%s$A1:IV65536] (", m_sSheetName);
|
||
for (int j = 0; j < m_aFieldNames.GetSize(); j++)
|
||
{
|
||
m_stempSql = m_stempSql + "[" + m_aFieldNames.GetAt(j) +"]" + " char(255), ";
|
||
}
|
||
m_stempSql.Delete(m_stempSql.GetLength()-2, 2);
|
||
m_stempSql += ")";
|
||
}
|
||
else
|
||
{
|
||
// 创建一个新的表格
|
||
m_stempSql.Format("CREATE TABLE [%s] (", m_sSheetName);
|
||
for (int i = 0; i < m_aFieldNames.GetSize(); i++)
|
||
{
|
||
m_stempSql = m_stempSql + "[" + m_aFieldNames.GetAt(i) +"]" + " char(255), ";
|
||
}
|
||
m_stempSql.Delete(m_stempSql.GetLength()-2, 2);
|
||
m_stempSql += ")";
|
||
}
|
||
|
||
try
|
||
{
|
||
m_Database->ExecuteSQL(m_stempSql);
|
||
if (!m_bAppend)
|
||
{
|
||
m_dTotalColumns = m_aFieldNames.GetSize();
|
||
m_bAppend = true;
|
||
}
|
||
}
|
||
catch(CDBException *pEx)
|
||
{
|
||
m_sLastError = pEx->m_strError;
|
||
m_Database->Close();
|
||
pEx->Delete();
|
||
|
||
return false;
|
||
}
|
||
|
||
// 保存已改变的数据
|
||
for (int k = 1; k < m_dTotalRows; k++)
|
||
{
|
||
ReadRow(m_atempArray, k+1);
|
||
|
||
// 创建插入行SQL语句
|
||
m_stempSql.Format("INSERT INTO [%s$A1:IV%d] (", m_sSheetName, k);
|
||
for (int i = 0; i < m_atempArray.GetSize(); i++)
|
||
{
|
||
m_stempString.Format("[%s], ", m_aFieldNames.GetAt(i));
|
||
m_stempSql = m_stempSql + m_stempString;
|
||
}
|
||
m_stempSql.Delete(m_stempSql.GetLength()-2, 2);
|
||
m_stempSql += ") VALUES (";
|
||
for (int j = 0; j < m_atempArray.GetSize(); j++)
|
||
{
|
||
m_stempString.Format("'%s', ", m_atempArray.GetAt(j));
|
||
m_stempSql = m_stempSql + m_stempString;
|
||
}
|
||
m_stempSql.Delete(m_stempSql.GetLength()-2, 2);
|
||
m_stempSql += ")";
|
||
|
||
// 插入行
|
||
try
|
||
{
|
||
m_Database->ExecuteSQL(m_stempSql);
|
||
}
|
||
catch(CDBException *pEx)
|
||
{
|
||
m_sLastError = pEx->m_strError;
|
||
m_Database->Close();
|
||
pEx->Delete();
|
||
return false;
|
||
}
|
||
}
|
||
m_Database->Close();
|
||
m_bTransaction = false;
|
||
return true;
|
||
}
|
||
else // 当文件是分隔符分隔的文本文件时
|
||
{
|
||
try
|
||
{
|
||
CFile *File = NULL;
|
||
File = new CFile(m_sFile, CFile::modeCreate | CFile::modeWrite | CFile::shareDenyNone);
|
||
if (File != NULL)
|
||
{
|
||
CArchive *Archive = NULL;
|
||
Archive = new CArchive(File, CArchive::store);
|
||
if (Archive != NULL)
|
||
{
|
||
for (int i = 0; i < m_aRows.GetSize(); i++)
|
||
{
|
||
Archive->WriteString(m_aRows.GetAt(i));
|
||
Archive->WriteString("\r\n");
|
||
}
|
||
delete Archive;
|
||
delete File;
|
||
m_bTransaction = false;
|
||
return true;
|
||
}
|
||
delete File;
|
||
}
|
||
}
|
||
catch(...)
|
||
{
|
||
}
|
||
m_sLastError = "写文件时产生错误\n";
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// 回滚文件改变为改变前状态
|
||
bool CSpreadSheet::RollBack()
|
||
{
|
||
if (Open())
|
||
{
|
||
m_bTransaction = false;
|
||
return true;
|
||
}
|
||
|
||
m_sLastError = "在回滚先前状态时产生错误\n";
|
||
|
||
return false;
|
||
}
|
||
|
||
// 转换为指定分隔符的文本或表格文件
|
||
bool CSpreadSheet::Convert(CString SheetOrSeparator)
|
||
{
|
||
// 文件名
|
||
m_stempString = m_sFile;
|
||
m_stempString.Delete(m_stempString.GetLength()-4, 4);
|
||
if (m_bExcel) // 当文件是Excel文件时
|
||
{
|
||
m_stempString += ".csv";
|
||
CSpreadSheet tempSheet(m_stempString, SheetOrSeparator, false);
|
||
|
||
// 如果指定文本文件已存在,存不转换直接返回
|
||
if (0 != tempSheet.GetTotalColumns())
|
||
{
|
||
return false;
|
||
}
|
||
|
||
tempSheet.BeginTransaction();
|
||
|
||
for (int i = 1; i <= m_dTotalRows; i++)
|
||
{
|
||
if (!ReadRow(m_atempArray, i))
|
||
{
|
||
return false;
|
||
}
|
||
if (!tempSheet.AddRow(m_atempArray, i))
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
if (!tempSheet.Commit())
|
||
{
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
else // 当文件是分隔符分隔的文本文件时
|
||
{
|
||
m_stempString += ".xls";
|
||
CSpreadSheet tempSheet(m_stempString, SheetOrSeparator, false);
|
||
|
||
// 如果指定Excel文件已存在,则直接返回
|
||
if (0 != tempSheet.GetTotalColumns())
|
||
{
|
||
return false;
|
||
}
|
||
|
||
GetFieldNames(m_atempArray);
|
||
|
||
// 检查首行(列头)字段是否重复
|
||
bool duplicate = false;
|
||
for (int i = 0; i < m_atempArray.GetSize(); i++)
|
||
{
|
||
for (int j = 0; j < m_atempArray.GetSize(); j++)
|
||
{
|
||
if ((i != j) && (m_atempArray.GetAt(i) == m_atempArray.GetAt(j)))
|
||
{
|
||
m_sLastError.Format("首行(列头)字段重复:%s\n", m_atempArray.GetAt(i));
|
||
duplicate = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (duplicate) // 重复时创建哑元首行(列头)
|
||
{
|
||
m_atempArray.RemoveAll();
|
||
for (int k = 1; k <= m_dTotalColumns; k++)
|
||
{
|
||
m_stempString.Format("%d", k);
|
||
m_atempArray.Add(m_stempString);
|
||
}
|
||
|
||
if (!tempSheet.AddHeaders(m_atempArray))
|
||
{
|
||
return false;
|
||
}
|
||
|
||
for (int l = 1; l <= m_dTotalRows; l++)
|
||
{
|
||
if (!ReadRow(m_atempArray, l))
|
||
{
|
||
return false;
|
||
}
|
||
if (!tempSheet.AddRow(m_atempArray, l+1))
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
else
|
||
{
|
||
if (!tempSheet.AddHeaders(m_atempArray))
|
||
{
|
||
return false;
|
||
}
|
||
|
||
for (int l = 2; l <= m_dTotalRows; l++)
|
||
{
|
||
if (!ReadRow(m_atempArray, l))
|
||
{
|
||
return false;
|
||
}
|
||
if (!tempSheet.AddRow(m_atempArray, l))
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 为进行读写打开Excel或分隔符分隔文本文件
|
||
bool CSpreadSheet::Open()
|
||
{
|
||
if (m_bExcel) // 当文件是Excel电子表格文件时
|
||
{
|
||
// 打开或创建Excel文件
|
||
m_Database->OpenEx(m_sDsn, CDatabase::noOdbcDialog);
|
||
|
||
// 创建记录集并查询表
|
||
m_rSheet = new CRecordset( m_Database );
|
||
m_sSql.Format("SELECT * FROM [%s$A1:IV65536]", m_sSheetName);
|
||
try
|
||
{
|
||
// 查询表
|
||
m_rSheet->Open(CRecordset::forwardOnly, m_sSql, CRecordset::readOnly);
|
||
}
|
||
catch(...)
|
||
{
|
||
// 表不存在
|
||
delete m_rSheet;
|
||
m_rSheet = NULL;
|
||
m_Database->Close();
|
||
return false;
|
||
}
|
||
|
||
// 得到列数
|
||
m_dTotalColumns = m_rSheet->m_nResultCols;
|
||
|
||
if (m_dTotalColumns != 0)
|
||
{
|
||
m_aRows.RemoveAll();
|
||
m_stempString.Empty();
|
||
m_bAppend = true;
|
||
m_dTotalRows++; // 总行数
|
||
|
||
// 获取首行(列头)字段名
|
||
for (int i = 0; i < m_dTotalColumns; i++)
|
||
{
|
||
m_stempSql = m_rSheet->m_rgODBCFieldInfos[i].m_strName;
|
||
m_aFieldNames.Add(m_stempSql);
|
||
|
||
// 将所有列合并到一个字符串中
|
||
if (i != m_dTotalColumns-1) // 不是最后一列
|
||
{
|
||
m_stempString = m_stempString + "\"" + m_stempSql + "\"" + m_sSeparator;
|
||
}
|
||
else // 最后一列
|
||
{
|
||
m_stempString = m_stempString + "\"" + m_stempSql + "\"";
|
||
}
|
||
}
|
||
|
||
// 存储内存中首行(列头)
|
||
m_aRows.Add(m_stempString);
|
||
|
||
// 读取并存储内存中其它行
|
||
while (!m_rSheet->IsEOF())
|
||
{
|
||
m_dTotalRows++; // 总行数
|
||
|
||
try
|
||
{
|
||
// 获取一行中所有列
|
||
m_stempString.Empty();
|
||
for (short column = 0; column < m_dTotalColumns; column++)
|
||
{
|
||
m_rSheet->GetFieldValue(column, m_stempSql);
|
||
|
||
// 将所有列合并到一个字符串中
|
||
if (column != m_dTotalColumns-1) // 不是最后列时
|
||
{
|
||
m_stempString = m_stempString + "\"" + m_stempSql + "\"" + m_sSeparator;
|
||
}
|
||
else // 最后一列时
|
||
{
|
||
m_stempString = m_stempString + "\"" + m_stempSql + "\"";
|
||
}
|
||
}
|
||
|
||
// 存储内存中已包含的行
|
||
m_aRows.Add(m_stempString);
|
||
m_rSheet->MoveNext();
|
||
}
|
||
catch (...)
|
||
{
|
||
m_sLastError = "读取行时产生错误\n";
|
||
delete m_rSheet;
|
||
m_rSheet = NULL;
|
||
m_Database->Close();
|
||
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
|
||
m_rSheet->Close();
|
||
delete m_rSheet;
|
||
m_rSheet = NULL;
|
||
m_Database->Close();
|
||
m_dCurrentRow = 1;
|
||
|
||
return true;
|
||
}
|
||
else // 当文件是指定分隔符分隔的文本文件时
|
||
{
|
||
try
|
||
{
|
||
CFile *File = NULL;
|
||
File = new CFile(m_sFile, CFile::modeRead | CFile::shareDenyNone);
|
||
if (File != NULL)
|
||
{
|
||
CArchive *Archive = NULL;
|
||
Archive = new CArchive(File, CArchive::load);
|
||
if (Archive != NULL)
|
||
{
|
||
m_aRows.RemoveAll();
|
||
// 读取并存储内存中所有行
|
||
while(Archive->ReadString(m_stempString))
|
||
{
|
||
m_aRows.Add(m_stempString);
|
||
}
|
||
ReadRow(m_aFieldNames, 1); // 得到首行的字段名(列头)
|
||
delete Archive;
|
||
delete File;
|
||
|
||
// 得到总行数
|
||
m_dTotalRows = m_aRows.GetSize();
|
||
|
||
// 获取最大总列数
|
||
for (int i = 0; i < m_aRows.GetSize(); i++)
|
||
{
|
||
ReadRow(m_atempArray, i);
|
||
if (m_atempArray.GetSize() > m_dTotalColumns)
|
||
{
|
||
m_dTotalColumns = m_atempArray.GetSize();
|
||
}
|
||
}
|
||
|
||
if (m_dTotalColumns != 0)
|
||
{
|
||
m_bAppend = true;
|
||
}
|
||
return true;
|
||
}
|
||
delete File;
|
||
}
|
||
}
|
||
catch(...)
|
||
{
|
||
}
|
||
|
||
m_sLastError = "打开文件时产生错误\n";
|
||
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// 转换Excle中字母列号为对应数字列号
|
||
short CSpreadSheet::CalculateColumnNumber(CString column, bool Auto)
|
||
{
|
||
if (Auto)
|
||
{
|
||
column.MakeUpper();
|
||
|
||
int firstLetter, secondLetter;
|
||
if (1 == column.GetLength())
|
||
{
|
||
firstLetter = column.GetAt(0);
|
||
return (firstLetter - 65 + 1); // ASCII码中大写字母A为65
|
||
}
|
||
else if (2 == column.GetLength())
|
||
{
|
||
firstLetter = column.GetAt(0);
|
||
secondLetter = column.GetAt(1);
|
||
return ((firstLetter - 65 + 1)*26 + (secondLetter - 65 + 1)); // ASCII码中大写字母A为65
|
||
}
|
||
}
|
||
|
||
// 检查是否是有效的字段名,有效直接返回
|
||
for (int i = 0; i < m_aFieldNames.GetSize(); i++)
|
||
{
|
||
if (!column.Compare(m_aFieldNames.GetAt(i)))
|
||
{
|
||
return (i + 1);
|
||
}
|
||
}
|
||
|
||
m_sLastError = "无效字段名或字母列号\n";
|
||
|
||
return 0;
|
||
}
|
||
|
||
// 获取Excel-ODBC驱动程序名字
|
||
void CSpreadSheet::GetExcelDriver()
|
||
{
|
||
char szBuf[2001];
|
||
WORD cbBufMax = 2000;
|
||
WORD cbBufOut;
|
||
char *pszBuf = szBuf;
|
||
|
||
// 获取已安装驱动程序的名字 (需要包含头文件"odbcinst.h")
|
||
if(!SQLGetInstalledDrivers(szBuf,cbBufMax,& cbBufOut))
|
||
{
|
||
m_sExcelDriver = "";
|
||
}
|
||
|
||
// 寻找Excel驱动程序...
|
||
do
|
||
{
|
||
if( NULL != strstr( pszBuf, "Excel" ) )
|
||
{
|
||
// 找到!
|
||
m_sExcelDriver = CString( pszBuf );
|
||
break;
|
||
}
|
||
pszBuf = strchr( pszBuf, '\0' ) + 1;
|
||
}
|
||
while( '\0' != pszBuf[1] );
|
||
}
|
||
|
||
#endif |