CSpreadSheet.h
上传用户:aymxxn
上传日期:2014-11-29
资源大小:135k
文件大小:33k
源码类别:

文件操作

开发平台:

Visual C++

  1. // Class to read and write to Excel and text delimited spreadsheet
  2. //
  3. // Created by Yap Chun Wei
  4. // December 2001
  5. // 
  6. // Version 1.1
  7. // Updates: Fix bug in ReadRow() which prevent reading of single column spreadsheet
  8. // Modified by jingzhou xu
  9. #ifndef CSPREADSHEET_H
  10. #define CSPREADSHEET_H
  11. #include <odbcinst.h>
  12. #include <afxdb.h>
  13. class CSpreadSheet
  14. {
  15. public:
  16. CSpreadSheet(CString File, CString SheetOrSeparator, bool Backup = true); // Open spreadsheet for reading and writing
  17. ~CSpreadSheet(); // Perform some cleanup functions
  18. bool AddHeaders(CStringArray &FieldNames, bool replace = false); // Add header row to spreadsheet
  19. bool DeleteSheet(); // Clear text delimited file content
  20. bool DeleteSheet(CString SheetName); // Clear entire Excel spreadsheet content. The sheet itself is not deleted
  21. bool AddRow(CStringArray &RowValues, long row = 0, bool replace = false); // Insert or replace a row into spreadsheet. Default is add new row. 
  22. bool AddCell(CString CellValue, CString column, long row = 0, bool Auto = true); // Replace or add a cell into Excel spreadsheet using header row or column alphabet. Default is add cell into new row. Set Auto to false if want to force column to be used as header name
  23. bool AddCell(CString CellValue, short column, long row = 0); // Replace or add a cell into spreadsheet using column number. Default is add cell into new row. 
  24. bool ReplaceRows(CStringArray &NewRowValues, CStringArray &OldRowValues); // Search and replace rows in Excel spreadsheet
  25. bool ReadRow(CStringArray &RowValues, long row = 0); // Read a row from spreadsheet. Default is read the next row
  26. bool ReadColumn(CStringArray &ColumnValues, CString column, bool Auto = true); // Read a column from Excel spreadsheet using header row or column alphabet. Set Auto to false if want to force column to be used as header name
  27. bool ReadColumn(CStringArray &ColumnValues, short column); // Read a column from spreadsheet using column number
  28. bool ReadCell (CString &CellValue, CString column, long row = 0, bool Auto = true); // Read a cell from Excel spreadsheet using header row or column alphabet. Default is read the next cell in next row. Set Auto to false if want to force column to be used as header name
  29. bool ReadCell (CString &CellValue, short column, long row = 0); // Read a cell from spreadsheet using column number. Default is read the next cell in next row.
  30. void BeginTransaction(); // Begin transaction
  31. bool Commit(); // Save changes to spreadsheet
  32. bool RollBack(); // Undo changes to spreadsheet
  33. bool Convert(CString SheetOrSeparator);
  34. inline void GetFieldNames (CStringArray &FieldNames) {FieldNames.RemoveAll(); FieldNames.Copy(m_aFieldNames);} // Get the header row from spreadsheet
  35. inline long GetTotalRows() {return m_dTotalRows;} // Get total number of rows in  spreadsheet
  36. inline short GetTotalColumns() {return m_dTotalColumns;} // Get total number of columns in  spreadsheet
  37. inline long GetCurrentRow() {return m_dCurrentRow;} // Get the currently selected row in  spreadsheet
  38. inline bool GetBackupStatus() {return m_bBackup;} // Get status of backup. True if backup is successful, False if spreadsheet is not backup
  39. inline bool GetTransactionStatus() {return m_bTransaction;} // Get status of Transaction. True if Transaction is started, False if Transaction is not started or has error in starting
  40. inline CString GetLastError() {return m_sLastError;} // Get last error message
  41. private:
  42. bool Open(); // Open a text delimited file for reading or writing
  43. void GetExcelDriver(); // Get the name of the Excel-ODBC driver
  44. short CalculateColumnNumber(CString column, bool Auto); // Convert Excel column in alphabet into column number
  45. bool m_bAppend; // Internal flag to denote newly created spreadsheet or previously created spreadsheet
  46. bool m_bBackup; // Internal flag to denote status of Backup
  47. bool m_bExcel; // Internal flag to denote whether file is Excel spreadsheet or text delimited spreadsheet
  48. bool m_bTransaction; // Internal flag to denote status of Transaction
  49. long m_dCurrentRow; // Index of current row, starting from 1
  50. long m_dTotalRows; // Total number of rows in spreadsheet
  51. short m_dTotalColumns; // Total number of columns in Excel spreadsheet. Largest number of columns in text delimited spreadsheet
  52. CString m_sSql; // SQL statement to open Excel spreadsheet for reading
  53. CString m_sDsn; // DSN string to open Excel spreadsheet for reading and writing
  54. CString m_stempSql; // Temporary string for SQL statements or for use by functions
  55. CString m_stempString; // Temporary string for use by functions
  56. CString m_sSheetName; // Sheet name of Excel spreadsheet
  57. CString m_sExcelDriver; // Name of Excel Driver
  58. CString m_sFile; // Spreadsheet file name
  59. CString m_sSeparator; // Separator in text delimited spreadsheet
  60. CString m_sLastError; // Last error message
  61. CStringArray m_atempArray; // Temporary array for use by functions
  62. CStringArray m_aFieldNames; // Header row in spreadsheet
  63. CStringArray m_aRows; // Content of all the rows in spreadsheet
  64. CDatabase *m_Database; // Database variable for Excel spreadsheet
  65. CRecordset *m_rSheet; // Recordset for Excel spreadsheet
  66. };
  67. // Open spreadsheet for reading and writing
  68. CSpreadSheet::CSpreadSheet(CString File, CString SheetOrSeparator, bool Backup) :
  69. m_Database(NULL), m_rSheet(NULL), m_sFile(File),
  70. m_dTotalRows(0), m_dTotalColumns(0), m_dCurrentRow(1),
  71. m_bAppend(false), m_bBackup(Backup), m_bTransaction(false)
  72. {
  73. // Detect whether file is an Excel spreadsheet or a text delimited file
  74. m_stempString = m_sFile.Right(4);
  75. m_stempString.MakeLower();
  76. if (m_stempString == ".xls") // File is an Excel spreadsheet
  77. {
  78. m_bExcel = true;
  79. m_sSheetName = SheetOrSeparator;
  80. m_sSeparator = ",;.?";
  81. }
  82. else // File is a text delimited file
  83. {
  84. m_bExcel = false;
  85. m_sSeparator = SheetOrSeparator;
  86. }
  87. if (m_bExcel) // If file is an Excel spreadsheet
  88. {
  89. m_Database = new CDatabase;
  90. GetExcelDriver();
  91. m_sDsn.Format("DRIVER={%s};DSN='';FIRSTROWHASNAMES=1;READONLY=FALSE;CREATE_DB="%s";DBQ=%s", m_sExcelDriver, m_sFile, m_sFile);
  92. if (Open())
  93. {
  94. if (m_bBackup)
  95. {
  96. if ((m_bBackup) && (m_bAppend))
  97. {
  98. CString tempSheetName = m_sSheetName;
  99. m_sSheetName = "CSpreadSheetBackup";
  100. m_bAppend = false;
  101. if (!Commit())
  102. {
  103. m_bBackup = false;
  104. }
  105. m_bAppend = true;
  106. m_sSheetName = tempSheetName;
  107. m_dCurrentRow = 1;
  108. }
  109. }
  110. }
  111. }
  112. else // if file is a text delimited file
  113. {
  114. if (Open())
  115. {
  116. if ((m_bBackup) && (m_bAppend))
  117. {
  118. m_stempString = m_sFile;
  119. m_stempSql.Format("%s.bak", m_sFile);
  120. m_sFile = m_stempSql;
  121. if (!Commit())
  122. {
  123. m_bBackup = false;
  124. }
  125. m_sFile = m_stempString;
  126. }
  127. }
  128. }
  129. }
  130. // Perform some cleanup functions
  131. CSpreadSheet::~CSpreadSheet()
  132. {
  133. if (m_Database != NULL)
  134. {
  135. m_Database->Close();
  136. delete m_Database;
  137. }
  138. }
  139. // Add header row to spreadsheet
  140. bool CSpreadSheet::AddHeaders(CStringArray &FieldNames, bool replace)
  141. {
  142. if (m_bAppend) // Append to old Sheet
  143. {
  144. if (replace) // Replacing header row rather than adding new columns
  145. {
  146. if (!AddRow(FieldNames, 1, true))
  147. {
  148. return false;
  149. }
  150. else
  151. {
  152. return true;
  153. }
  154. }
  155. if (ReadRow(m_atempArray, 1)) // Add new columns
  156. {
  157. if (m_bExcel)
  158. {
  159. // Check for duplicate header row field
  160. for (int i = 0; i < FieldNames.GetSize(); i++)
  161. {
  162. for (int j = 0; j < m_atempArray.GetSize(); j++)
  163. {
  164. if (FieldNames.GetAt(i) == m_atempArray.GetAt(j))
  165. {
  166. m_sLastError.Format("Duplicate header row field:%sn", FieldNames.GetAt(i));
  167. return false;
  168. }
  169. }
  170. }
  171. }
  172. m_atempArray.Append(FieldNames);
  173. if (!AddRow(m_atempArray, 1, true))
  174. {
  175. m_sLastError = "Problems with adding headersn";
  176. return false;
  177. }
  178. // Update largest number of columns if necessary
  179. if (m_atempArray.GetSize() > m_dTotalColumns)
  180. {
  181. m_dTotalColumns = m_atempArray.GetSize();
  182. }
  183. return true;
  184. }
  185. return false;
  186. }
  187. else // New Sheet
  188. {
  189. m_dTotalColumns = FieldNames.GetSize();
  190. if (!AddRow(FieldNames, 1, true))
  191. {
  192. return false;
  193. }
  194. else
  195. {
  196. m_dTotalRows = 1;
  197. return true;
  198. }
  199. }
  200. }
  201. // Clear text delimited file content
  202. bool CSpreadSheet::DeleteSheet()
  203. {
  204. if (m_bExcel)
  205. {
  206. if (DeleteSheet(m_sSheetName))
  207. {
  208. return true;
  209. }
  210. else
  211. {
  212. m_sLastError = "Error deleting sheetn";
  213. return false;
  214. }
  215. }
  216. else
  217. {
  218. m_aRows.RemoveAll();
  219. m_aFieldNames.RemoveAll();
  220. m_dTotalColumns = 0;
  221. m_dTotalRows = 0;
  222. if (!m_bTransaction)
  223. {
  224. Commit();
  225. }
  226. m_bAppend = false; // Set flag to new sheet
  227. return true;
  228. }
  229. }
  230. // Clear entire Excel spreadsheet content. The sheet itself is not deleted
  231. bool CSpreadSheet::DeleteSheet(CString SheetName)
  232. {
  233. if (m_bExcel) // If file is an Excel spreadsheet
  234. {
  235. // Delete sheet
  236. m_Database->OpenEx(m_sDsn, CDatabase::noOdbcDialog);
  237. SheetName = "[" + SheetName + "$A1:IV65536]";
  238. m_stempSql.Format ("DROP TABLE %s", SheetName);
  239. try
  240. {
  241. m_Database->ExecuteSQL(m_stempSql);
  242. m_Database->Close();
  243. m_aRows.RemoveAll();
  244. m_aFieldNames.RemoveAll();
  245. m_dTotalColumns = 0;
  246. m_dTotalRows = 0;
  247. }
  248. catch(CDBException *e)
  249. {
  250. m_sLastError = e->m_strError;
  251. m_Database->Close();
  252. return false;
  253. }
  254. return true;
  255. }
  256. else // if file is a text delimited file
  257. {
  258. return DeleteSheet();
  259. }
  260. }
  261. // Insert or replace a row into spreadsheet. 
  262. // Default is add new row.
  263. bool CSpreadSheet::AddRow(CStringArray &RowValues, long row, bool replace)
  264. {
  265. long tempRow;
  266. if (row == 1)
  267. {
  268. if (m_bExcel) 
  269. {
  270. // Check for duplicate header row field for Excel spreadsheet
  271. for (int i = 0; i < RowValues.GetSize(); i++)
  272. {
  273. for (int j = 0; j < RowValues.GetSize(); j++)
  274. {
  275. if ((i != j) && (RowValues.GetAt(i) == RowValues.GetAt(j)))
  276. {
  277. m_sLastError.Format("Duplicate header row field:%sn", RowValues.GetAt(i));
  278. return false;
  279. }
  280. }
  281. }
  282. // Check for reduced header row columns
  283. if (RowValues.GetSize() < m_dTotalColumns)
  284. {
  285. m_sLastError = "Number of columns in new header row cannot be less than the number of columns in previous header row";
  286. return false;
  287. }
  288. m_dTotalColumns = RowValues.GetSize();
  289. }
  290. // Update header row
  291. m_aFieldNames.RemoveAll();
  292. m_aFieldNames.Copy(RowValues);
  293. }
  294. else
  295. {
  296. if (m_bExcel)
  297. {
  298. if (m_dTotalColumns == 0)
  299. {
  300. m_sLastError = "No header row. Add header row firstn";
  301. return false;
  302. }
  303. }
  304. }
  305. if (m_bExcel) // For Excel spreadsheet
  306. {
  307. if (RowValues.GetSize() > m_aFieldNames.GetSize())
  308. {
  309. m_sLastError = "Number of columns to be added cannot be greater than the number of fieldsn";
  310. return false;
  311. }
  312. }
  313. else // For text delimited spreadsheet
  314. {
  315. // Update largest number of columns if necessary
  316. if (RowValues.GetSize() > m_dTotalColumns)
  317. {
  318. m_dTotalColumns = RowValues.GetSize();
  319. }
  320. }
  321. // Convert row values
  322. m_stempString.Empty();
  323. for (int i = 0; i < RowValues.GetSize(); i++)
  324. {
  325. if (i != RowValues.GetSize()-1) // Not last column
  326. {
  327. m_stempSql.Format(""%s"%s", RowValues.GetAt(i), m_sSeparator);
  328. m_stempString += m_stempSql;
  329. }
  330. else // Last column
  331. {
  332. m_stempSql.Format(""%s"", RowValues.GetAt(i));
  333. m_stempString += m_stempSql;
  334. }
  335. }
  336. if (row)
  337. {
  338. if (row <= m_dTotalRows) // Not adding new rows
  339. {
  340. if (replace) // Replacing row
  341. {
  342. m_aRows.SetAt(row-1, m_stempString);
  343. }
  344. else // Inserting row
  345. {
  346. m_aRows.InsertAt(row-1, m_stempString);
  347. m_dTotalRows++;
  348. }
  349. if (!m_bTransaction)
  350. {
  351. Commit();
  352. }
  353. return true;
  354. }
  355. else // Adding new rows
  356. {
  357. // Insert null rows until specified row
  358. m_dCurrentRow = m_dTotalRows;
  359. m_stempSql.Empty();
  360. CString nullString;
  361. for (int i = 1; i <= m_dTotalColumns; i++)
  362. {
  363. if (i != m_dTotalColumns)
  364. {
  365. if (m_bExcel)
  366. {
  367. nullString.Format("" "%s", m_sSeparator);
  368. }
  369. else
  370. {
  371. nullString.Format("""%s", m_sSeparator);
  372. }
  373. m_stempSql += nullString;
  374. }
  375. else
  376. {
  377. if (m_bExcel)
  378. {
  379. m_stempSql += "" "";
  380. }
  381. else
  382. {
  383. m_stempSql += """";
  384. }
  385. }
  386. }
  387. for (int j = m_dTotalRows + 1; j < row; j++)
  388. {
  389. m_dCurrentRow++;
  390. m_aRows.Add(m_stempSql);
  391. }
  392. }
  393. }
  394. else
  395. {
  396. tempRow = m_dCurrentRow;
  397. m_dCurrentRow = m_dTotalRows;
  398. }
  399. // Insert new row
  400. m_dCurrentRow++;
  401. m_aRows.Add(m_stempString);
  402. if (row > m_dTotalRows)
  403. {
  404. m_dTotalRows = row;
  405. }
  406. else if (!row)
  407. {
  408. m_dTotalRows = m_dCurrentRow;
  409. m_dCurrentRow = tempRow;
  410. }
  411. if (!m_bTransaction)
  412. {
  413. Commit();
  414. }
  415. return true;
  416. }
  417. // Replace or add a cell into Excel spreadsheet using header row or column alphabet. 
  418. // Default is add cell into new row.
  419. // Set Auto to false if want to force column to be used as header name
  420. bool CSpreadSheet::AddCell(CString CellValue, CString column, long row, bool Auto)
  421. {
  422. short columnIndex = CalculateColumnNumber(column, Auto);
  423. if (columnIndex == 0)
  424. {
  425. return false;
  426. }
  427. if (AddCell(CellValue, columnIndex, row))
  428. {
  429. return true;
  430. }
  431. return false;
  432. }
  433. // Replace or add a cell into spreadsheet using column number
  434. // Default is add cell into new row.
  435. bool CSpreadSheet::AddCell(CString CellValue, short column, long row)
  436. {
  437. if (column == 0)
  438. {
  439. m_sLastError = "Column cannot be zeron";
  440. return false;
  441. }
  442. long tempRow;
  443. if (m_bExcel) // For Excel spreadsheet
  444. {
  445. if (column > m_aFieldNames.GetSize() + 1)
  446. {
  447. m_sLastError = "Cell column to be added cannot be greater than the number of fieldsn";
  448. return false;
  449. }
  450. }
  451. else // For text delimited spreadsheet
  452. {
  453. // Update largest number of columns if necessary
  454. if (column > m_dTotalColumns)
  455. {
  456. m_dTotalColumns = column;
  457. }
  458. }
  459. if (row)
  460. {
  461. if (row <= m_dTotalRows)
  462. {
  463. ReadRow(m_atempArray, row);
  464. // Change desired row
  465. m_atempArray.SetAtGrow(column-1, CellValue);
  466. if (row == 1)
  467. {
  468. if (m_bExcel) // Check for duplicate header row field
  469. {
  470. for (int i = 0; i < m_atempArray.GetSize(); i++)
  471. {
  472. for (int j = 0; j < m_atempArray.GetSize(); j++)
  473. {
  474. if ((i != j) && (m_atempArray.GetAt(i) == m_atempArray.GetAt(j)))
  475. {
  476. m_sLastError.Format("Duplicate header row field:%sn", m_atempArray.GetAt(i));
  477. return false;
  478. }
  479. }
  480. }
  481. }
  482. // Update header row
  483. m_aFieldNames.RemoveAll();
  484. m_aFieldNames.Copy(m_atempArray);
  485. }
  486. if (!AddRow(m_atempArray, row, true))
  487. {
  488. return false;
  489. }
  490. if (!m_bTransaction)
  491. {
  492. Commit();
  493. }
  494. return true;
  495. }
  496. else
  497. {
  498. // Insert null rows until specified row
  499. m_dCurrentRow = m_dTotalRows;
  500. m_stempSql.Empty();
  501. CString nullString;
  502. for (int i = 1; i <= m_dTotalColumns; i++)
  503. {
  504. if (i != m_dTotalColumns)
  505. {
  506. if (m_bExcel)
  507. {
  508. nullString.Format("" "%s", m_sSeparator);
  509. }
  510. else
  511. {
  512. nullString.Format("""%s", m_sSeparator);
  513. }
  514. m_stempSql += nullString;
  515. }
  516. else
  517. {
  518. if (m_bExcel)
  519. {
  520. m_stempSql += "" "";
  521. }
  522. else
  523. {
  524. m_stempSql += """";
  525. }
  526. }
  527. }
  528. for (int j = m_dTotalRows + 1; j < row; j++)
  529. {
  530. m_dCurrentRow++;
  531. m_aRows.Add(m_stempSql);
  532. }
  533. }
  534. }
  535. else
  536. {
  537. tempRow = m_dCurrentRow;
  538. m_dCurrentRow = m_dTotalRows;
  539. }
  540. // Insert cell
  541. m_dCurrentRow++;
  542. m_stempString.Empty();
  543. for (int j = 1; j <= m_dTotalColumns; j++)
  544. {
  545. if (j != m_dTotalColumns) // Not last column
  546. {
  547. if (j != column)
  548. {
  549. if (m_bExcel)
  550. {
  551. m_stempSql.Format("" "%s", m_sSeparator);
  552. }
  553. else
  554. {
  555. m_stempSql.Format("""%s", m_sSeparator);
  556. }
  557. m_stempString += m_stempSql;
  558. }
  559. else
  560. {
  561. m_stempSql.Format(""%s"%s", CellValue, m_sSeparator);
  562. m_stempString += m_stempSql;
  563. }
  564. }
  565. else // Last column
  566. {
  567. if (j != column)
  568. {
  569. if (m_bExcel)
  570. {
  571. m_stempString += "" "";
  572. }
  573. else
  574. {
  575. m_stempString += """";
  576. }
  577. }
  578. else
  579. {
  580. m_stempSql.Format(""%s"", CellValue);
  581. m_stempString += m_stempSql;
  582. }
  583. }
  584. }
  585. m_aRows.Add(m_stempString);
  586. if (row > m_dTotalRows)
  587. {
  588. m_dTotalRows = row;
  589. }
  590. else if (!row)
  591. {
  592. m_dTotalRows = m_dCurrentRow;
  593. m_dCurrentRow = tempRow;
  594. }
  595. if (!m_bTransaction)
  596. {
  597. Commit();
  598. }
  599. return true;
  600. }
  601. // Search and replace rows in Excel spreadsheet
  602. bool CSpreadSheet::ReplaceRows(CStringArray &NewRowValues, CStringArray &OldRowValues)
  603. {
  604. if (m_bExcel) // If file is an Excel spreadsheet
  605. {
  606. m_Database->OpenEx(m_sDsn, CDatabase::noOdbcDialog);
  607. m_stempSql.Format("UPDATE [%s] SET ", m_sSheetName);
  608. for (int i = 0; i < NewRowValues.GetSize(); i++)
  609. {
  610. m_stempString.Format("[%s]='%s', ", m_aFieldNames.GetAt(i), NewRowValues.GetAt(i));
  611. m_stempSql = m_stempSql + m_stempString;
  612. }
  613. m_stempSql.Delete(m_stempSql.GetLength()-2, 2);
  614. m_stempSql = m_stempSql + " WHERE (";
  615. for (int j = 0; j < OldRowValues.GetSize()-1; j++)
  616. {
  617. m_stempString.Format("[%s]='%s' AND ", m_aFieldNames.GetAt(j), OldRowValues.GetAt(j));
  618. m_stempSql = m_stempSql + m_stempString;
  619. }
  620. m_stempSql.Delete(m_stempSql.GetLength()-4, 5);
  621. m_stempSql += ")";
  622. try
  623. {
  624. m_Database->ExecuteSQL(m_stempSql);
  625. m_Database->Close();
  626. Open();
  627. return true;
  628. }
  629. catch(CDBException *e)
  630. {
  631. m_sLastError = e->m_strError;
  632. m_Database->Close();
  633. return false;
  634. }
  635. }
  636. else // if file is a text delimited file
  637. {
  638. m_sLastError = "Function not available for text delimited filen";
  639. return false;
  640. }
  641. }
  642. // Read a row from spreadsheet. 
  643. // Default is read the next row
  644. bool CSpreadSheet::ReadRow(CStringArray &RowValues, long row)
  645. {
  646. // Check if row entered is more than number of rows in sheet
  647. if (row <= m_aRows.GetSize())
  648. {
  649. if (row != 0)
  650. {
  651. m_dCurrentRow = row;
  652. }
  653. else if (m_dCurrentRow > m_aRows.GetSize())
  654. {
  655. return false;
  656. }
  657. // Read the desired row
  658. RowValues.RemoveAll();
  659. m_stempString = m_aRows.GetAt(m_dCurrentRow-1);
  660. m_dCurrentRow++;
  661. // Search for separator to split row
  662. int separatorPosition;
  663. m_stempSql.Format(""%s"", m_sSeparator);
  664. separatorPosition = m_stempString.Find(m_stempSql); // If separator is "?"
  665. if (separatorPosition != -1)
  666. {
  667. // Save columns
  668. int nCount = 0;
  669. int stringStartingPosition = 0;
  670. while (separatorPosition != -1)
  671. {
  672. nCount = separatorPosition - stringStartingPosition;
  673. RowValues.Add(m_stempString.Mid(stringStartingPosition, nCount));
  674. stringStartingPosition = separatorPosition + m_stempSql.GetLength();
  675. separatorPosition = m_stempString.Find(m_stempSql, stringStartingPosition);
  676. }
  677. nCount = m_stempString.GetLength() - stringStartingPosition;
  678. RowValues.Add(m_stempString.Mid(stringStartingPosition, nCount));
  679. // Remove quotes from first column
  680. m_stempString = RowValues.GetAt(0);
  681. m_stempString.Delete(0, 1);
  682. RowValues.SetAt(0, m_stempString);
  683. // Remove quotes from last column
  684. m_stempString = RowValues.GetAt(RowValues.GetSize()-1);
  685. m_stempString.Delete(m_stempString.GetLength()-1, 1);
  686. RowValues.SetAt(RowValues.GetSize()-1, m_stempString);
  687. return true;
  688. }
  689. else
  690. {
  691. // Save columns
  692. separatorPosition = m_stempString.Find(m_sSeparator); // if separator is ?
  693. if (separatorPosition != -1)
  694. {
  695. int nCount = 0;
  696. int stringStartingPosition = 0;
  697. while (separatorPosition != -1)
  698. {
  699. nCount = separatorPosition - stringStartingPosition;
  700. RowValues.Add(m_stempString.Mid(stringStartingPosition, nCount));
  701. stringStartingPosition = separatorPosition + m_sSeparator.GetLength();
  702. separatorPosition = m_stempString.Find(m_sSeparator, stringStartingPosition);
  703. }
  704. nCount = m_stempString.GetLength() - stringStartingPosition;
  705. RowValues.Add(m_stempString.Mid(stringStartingPosition, nCount));
  706. return true;
  707. }
  708. else // Treat spreadsheet as having one column
  709. {
  710. // Remove opening and ending quotes if any
  711. int quoteBegPos = m_stempString.Find('"');
  712. int quoteEndPos = m_stempString.ReverseFind('"');
  713. if ((quoteBegPos == 0) && (quoteEndPos == m_stempString.GetLength()-1))
  714. {
  715. m_stempString.Delete(0, 1);
  716. m_stempString.Delete(m_stempString.GetLength()-1, 1);
  717. }
  718. RowValues.Add(m_stempString);
  719. }
  720. }
  721. }
  722. m_sLastError = "Desired row is greater than total number of rows in spreadsheetn";
  723. return false;
  724. }
  725. // Read a column from Excel spreadsheet using header row or column alphabet. 
  726. // Set Auto to false if want to force column to be used as header name
  727. bool CSpreadSheet::ReadColumn(CStringArray &ColumnValues, CString column, bool Auto)
  728. {
  729. short columnIndex = CalculateColumnNumber(column, Auto);
  730. if (columnIndex == 0)
  731. {
  732. return false;
  733. }
  734. if (ReadColumn(ColumnValues, columnIndex))
  735. {
  736. return true;
  737. }
  738. return false;
  739. }
  740. // Read a column from spreadsheet using column number
  741. bool CSpreadSheet::ReadColumn(CStringArray &ColumnValues, short column)
  742. {
  743. if (column == 0)
  744. {
  745. m_sLastError = "Column cannot be zeron";
  746. return false;
  747. }
  748. int tempRow = m_dCurrentRow;
  749. m_dCurrentRow = 1;
  750. ColumnValues.RemoveAll();
  751. for (int i = 1; i <= m_aRows.GetSize(); i++)
  752. {
  753. // Read each row
  754. if (ReadRow(m_atempArray, i))
  755. {
  756. // Get value of cell in desired column
  757. if (column <= m_atempArray.GetSize())
  758. {
  759. ColumnValues.Add(m_atempArray.GetAt(column-1));
  760. }
  761. else
  762. {
  763. ColumnValues.Add("");
  764. }
  765. }
  766. else
  767. {
  768. m_dCurrentRow = tempRow;
  769. m_sLastError = "Error reading rown";
  770. return false;
  771. }
  772. }
  773. m_dCurrentRow = tempRow;
  774. return true;
  775. }
  776. // Read a cell from Excel spreadsheet using header row or column alphabet. 
  777. // Default is read the next cell in next row. 
  778. // Set Auto to false if want to force column to be used as header name
  779. bool CSpreadSheet::ReadCell (CString &CellValue, CString column, long row, bool Auto)
  780. {
  781. short columnIndex = CalculateColumnNumber(column, Auto);
  782. if (columnIndex == 0)
  783. {
  784. return false;
  785. }
  786. if (ReadCell(CellValue, columnIndex, row))
  787. {
  788. return true;
  789. }
  790. return false;
  791. }
  792. // Read a cell from spreadsheet using column number. 
  793. // Default is read the next cell in next row.
  794. bool CSpreadSheet::ReadCell (CString &CellValue, short column, long row)
  795. {
  796. if (column == 0)
  797. {
  798. m_sLastError = "Column cannot be zeron";
  799. return false;
  800. }
  801. int tempRow = m_dCurrentRow;
  802. if (row)
  803. {
  804. m_dCurrentRow = row;
  805. }
  806. if (ReadRow(m_atempArray, m_dCurrentRow))
  807. {
  808. // Get value of cell in desired column
  809. if (column <= m_atempArray.GetSize())
  810. {
  811. CellValue = m_atempArray.GetAt(column-1);
  812. }
  813. else
  814. {
  815. CellValue.Empty();
  816. m_dCurrentRow = tempRow;
  817. return false;
  818. }
  819. m_dCurrentRow = tempRow;
  820. return true;
  821. }
  822. m_dCurrentRow = tempRow;
  823. m_sLastError = "Error reading rown";
  824. return false;
  825. }
  826. // Begin transaction
  827. void CSpreadSheet::BeginTransaction()
  828. {
  829. m_bTransaction = true;
  830. }
  831. // Save changes to spreadsheet
  832. bool CSpreadSheet::Commit()
  833. {
  834. if (m_bExcel) // If file is an Excel spreadsheet
  835. {
  836. m_Database->OpenEx(m_sDsn, CDatabase::noOdbcDialog);
  837. if (m_bAppend)
  838. {
  839. // Delete old sheet if it exists
  840. m_stempString= "[" + m_sSheetName + "$A1:IV65536]";
  841. m_stempSql.Format ("DROP TABLE %s", m_stempString);
  842. try
  843. {
  844. m_Database->ExecuteSQL(m_stempSql);
  845. }
  846. catch(CDBException *e)
  847. {
  848. m_sLastError = e->m_strError;
  849. m_Database->Close();
  850. return false;
  851. }
  852. // Create new sheet
  853. m_stempSql.Format("CREATE TABLE [%s$A1:IV65536] (", m_sSheetName);
  854. for (int j = 0; j < m_aFieldNames.GetSize(); j++)
  855. {
  856. m_stempSql = m_stempSql + "[" + m_aFieldNames.GetAt(j) +"]" + " char(255), ";
  857. }
  858. m_stempSql.Delete(m_stempSql.GetLength()-2, 2);
  859. m_stempSql += ")";
  860. }
  861. else
  862. {
  863. // Create new sheet
  864. m_stempSql.Format("CREATE TABLE [%s] (", m_sSheetName);
  865. for (int i = 0; i < m_aFieldNames.GetSize(); i++)
  866. {
  867. m_stempSql = m_stempSql + "[" + m_aFieldNames.GetAt(i) +"]" + " char(255), ";
  868. }
  869. m_stempSql.Delete(m_stempSql.GetLength()-2, 2);
  870. m_stempSql += ")";
  871. }
  872. try
  873. {
  874. m_Database->ExecuteSQL(m_stempSql);
  875. if (!m_bAppend)
  876. {
  877. m_dTotalColumns = m_aFieldNames.GetSize();
  878. m_bAppend = true;
  879. }
  880. }
  881. catch(CDBException *e)
  882. {
  883. m_sLastError = e->m_strError;
  884. m_Database->Close();
  885. return false;
  886. }
  887. // Save changed data
  888. for (int k = 1; k < m_dTotalRows; k++)
  889. {
  890. ReadRow(m_atempArray, k+1);
  891. // Create Insert SQL
  892. m_stempSql.Format("INSERT INTO [%s$A1:IV%d] (", m_sSheetName, k);
  893. for (int i = 0; i < m_atempArray.GetSize(); i++)
  894. {
  895. m_stempString.Format("[%s], ", m_aFieldNames.GetAt(i));
  896. m_stempSql = m_stempSql + m_stempString;
  897. }
  898. m_stempSql.Delete(m_stempSql.GetLength()-2, 2);
  899. m_stempSql += ") VALUES (";
  900. for (int j = 0; j < m_atempArray.GetSize(); j++)
  901. {
  902. m_stempString.Format("'%s', ", m_atempArray.GetAt(j));
  903. m_stempSql = m_stempSql + m_stempString;
  904. }
  905. m_stempSql.Delete(m_stempSql.GetLength()-2, 2);
  906. m_stempSql += ")";
  907. // Add row
  908. try
  909. {
  910. m_Database->ExecuteSQL(m_stempSql);
  911. }
  912. catch(CDBException *e)
  913. {
  914. m_sLastError = e->m_strError;
  915. m_Database->Close();
  916. return false;
  917. }
  918. }
  919. m_Database->Close();
  920. m_bTransaction = false;
  921. return true;
  922. }
  923. else // if file is a text delimited file
  924. {
  925. try
  926. {
  927. CFile *File = NULL;
  928. File = new CFile(m_sFile, CFile::modeCreate | CFile::modeWrite  | CFile::shareDenyNone);
  929. if (File != NULL)
  930. {
  931. CArchive *Archive = NULL;
  932. Archive = new CArchive(File, CArchive::store);
  933. if (Archive != NULL)
  934. {
  935. for (int i = 0; i < m_aRows.GetSize(); i++)
  936. {
  937. Archive->WriteString(m_aRows.GetAt(i));
  938. Archive->WriteString("rn");
  939. }
  940. delete Archive;
  941. delete File;
  942. m_bTransaction = false;
  943. return true;
  944. }
  945. delete File;
  946. }
  947. }
  948. catch(...)
  949. {
  950. }
  951. m_sLastError = "Error writing filen";
  952. return false;
  953. }
  954. }
  955. // Undo changes to spreadsheet
  956. bool CSpreadSheet::RollBack()
  957. {
  958. if (Open())
  959. {
  960. m_bTransaction = false;
  961. return true;
  962. }
  963. m_sLastError = "Error in returning to previous staten";
  964. return false;
  965. }
  966. bool CSpreadSheet::Convert(CString SheetOrSeparator)
  967. {
  968. // Prepare file
  969. m_stempString = m_sFile;
  970. m_stempString.Delete(m_stempString.GetLength()-4, 4);
  971. if (m_bExcel) // If file is an Excel spreadsheet
  972. {
  973. m_stempString += ".csv";
  974. CSpreadSheet tempSheet(m_stempString, SheetOrSeparator, false);
  975. // Stop convert if text delimited file exists
  976. if (tempSheet.GetTotalColumns() != 0)
  977. {
  978. return false;
  979. }
  980. tempSheet.BeginTransaction();
  981. for (int i = 1; i <= m_dTotalRows; i++)
  982. {
  983. if (!ReadRow(m_atempArray, i))
  984. {
  985. return false;
  986. }
  987. if (!tempSheet.AddRow(m_atempArray, i))
  988. {
  989. return false;
  990. }
  991. }
  992. if (!tempSheet.Commit())
  993. {
  994. return false;
  995. }
  996. return true;
  997. }
  998. else // if file is a text delimited file
  999. {
  1000. m_stempString += ".xls";
  1001. CSpreadSheet tempSheet(m_stempString, SheetOrSeparator, false);
  1002. // Stop convert if Excel file exists
  1003. if (tempSheet.GetTotalColumns() != 0)
  1004. {
  1005. return false;
  1006. }
  1007. GetFieldNames(m_atempArray);
  1008. // Check for duplicate header row field
  1009. bool duplicate = false;
  1010. for (int i = 0; i < m_atempArray.GetSize(); i++)
  1011. {
  1012. for (int j = 0; j < m_atempArray.GetSize(); j++)
  1013. {
  1014. if ((i != j) && (m_atempArray.GetAt(i) == m_atempArray.GetAt(j)))
  1015. {
  1016. m_sLastError.Format("Duplicate header row field:%sn", m_atempArray.GetAt(i));
  1017. duplicate = true;
  1018. }
  1019. }
  1020. }
  1021. if (duplicate) // Create dummy header row
  1022. {
  1023. m_atempArray.RemoveAll();
  1024. for (int k = 1; k <= m_dTotalColumns; k++)
  1025. {
  1026. m_stempString.Format("%d", k);
  1027. m_atempArray.Add(m_stempString);
  1028. }
  1029. if (!tempSheet.AddHeaders(m_atempArray))
  1030. {
  1031. return false;
  1032. }
  1033. for (int l = 1; l <= m_dTotalRows; l++)
  1034. {
  1035. if (!ReadRow(m_atempArray, l))
  1036. {
  1037. return false;
  1038. }
  1039. if (!tempSheet.AddRow(m_atempArray, l+1))
  1040. {
  1041. return false;
  1042. }
  1043. }
  1044. return true;
  1045. }
  1046. else
  1047. {
  1048. if (!tempSheet.AddHeaders(m_atempArray))
  1049. {
  1050. return false;
  1051. }
  1052. for (int l = 2; l <= m_dTotalRows; l++)
  1053. {
  1054. if (!ReadRow(m_atempArray, l))
  1055. {
  1056. return false;
  1057. }
  1058. if (!tempSheet.AddRow(m_atempArray, l))
  1059. {
  1060. return false;
  1061. }
  1062. }
  1063. return true;
  1064. }
  1065. }
  1066. }
  1067. // Open a text delimited file for reading or writing
  1068. bool CSpreadSheet::Open()
  1069. {
  1070. if (m_bExcel) // If file is an Excel spreadsheet
  1071. {
  1072. m_Database->OpenEx(m_sDsn, CDatabase::noOdbcDialog);
  1073. // Open Sheet
  1074. m_rSheet = new CRecordset( m_Database );
  1075. m_sSql.Format("SELECT * FROM [%s$A1:IV65536]", m_sSheetName);
  1076. try
  1077. {
  1078. m_rSheet->Open(CRecordset::forwardOnly, m_sSql, CRecordset::readOnly);
  1079. }
  1080. catch(...)
  1081. {
  1082. delete m_rSheet;
  1083. m_rSheet = NULL;
  1084. m_Database->Close();
  1085. return false;
  1086. }
  1087. // Get number of columns
  1088. m_dTotalColumns = m_rSheet->m_nResultCols;
  1089. if (m_dTotalColumns != 0)
  1090. {
  1091. m_aRows.RemoveAll();
  1092. m_stempString.Empty();
  1093. m_bAppend = true;
  1094. m_dTotalRows++; // Keep count of total number of rows
  1095. // Get field names i.e header row
  1096. for (int i = 0; i < m_dTotalColumns; i++)
  1097. {
  1098. m_stempSql = m_rSheet->m_rgODBCFieldInfos[i].m_strName;
  1099. m_aFieldNames.Add(m_stempSql);
  1100. // Join up all the columns into a string
  1101. if (i != m_dTotalColumns-1) // Not last column
  1102. {
  1103. m_stempString = m_stempString + """ + m_stempSql + """ + m_sSeparator;
  1104. }
  1105. else // Last column
  1106. {
  1107. m_stempString = m_stempString + """ + m_stempSql + """;
  1108. }
  1109. }
  1110. // Store the header row as the first row in memory
  1111. m_aRows.Add(m_stempString);
  1112. // Read and store the rest of the rows in memory
  1113. while (!m_rSheet->IsEOF())
  1114. {
  1115. m_dTotalRows++; // Keep count of total number of rows
  1116. try
  1117. {
  1118. // Get all the columns in a row
  1119. m_stempString.Empty();
  1120. for (short column = 0; column < m_dTotalColumns; column++)
  1121. {
  1122. m_rSheet->GetFieldValue(column, m_stempSql);
  1123. // Join up all the columns into a string
  1124. if (column != m_dTotalColumns-1) // Not last column
  1125. {
  1126. m_stempString = m_stempString + """ + m_stempSql + """ + m_sSeparator;
  1127. }
  1128. else // Last column
  1129. {
  1130. m_stempString = m_stempString + """ + m_stempSql + """;
  1131. }
  1132. }
  1133. // Store the obtained row in memory
  1134. m_aRows.Add(m_stempString);
  1135. m_rSheet->MoveNext();
  1136. }
  1137. catch (...)
  1138. {
  1139. m_sLastError = "Error reading rown";
  1140. delete m_rSheet;
  1141. m_rSheet = NULL;
  1142. m_Database->Close();
  1143. return false;
  1144. }
  1145. }
  1146. }
  1147. m_rSheet->Close();
  1148. delete m_rSheet;
  1149. m_rSheet = NULL;
  1150. m_Database->Close();
  1151. m_dCurrentRow = 1;
  1152. return true;
  1153. }
  1154. else // if file is a text delimited file
  1155. {
  1156. try
  1157. {
  1158. CFile *File = NULL;
  1159. File = new CFile(m_sFile, CFile::modeRead | CFile::shareDenyNone);
  1160. if (File != NULL)
  1161. {
  1162. CArchive *Archive = NULL;
  1163. Archive = new CArchive(File, CArchive::load);
  1164. if (Archive != NULL)
  1165. {
  1166. m_aRows.RemoveAll();
  1167. // Read and store all rows in memory
  1168. while(Archive->ReadString(m_stempString))
  1169. {
  1170. m_aRows.Add(m_stempString);
  1171. }
  1172. ReadRow(m_aFieldNames, 1); // Get field names i.e header row
  1173. delete Archive;
  1174. delete File;
  1175. // Get total number of rows
  1176. m_dTotalRows = m_aRows.GetSize();
  1177. // Get the largest number of columns
  1178. for (int i = 0; i < m_aRows.GetSize(); i++)
  1179. {
  1180. ReadRow(m_atempArray, i);
  1181. if (m_atempArray.GetSize() > m_dTotalColumns)
  1182. {
  1183. m_dTotalColumns = m_atempArray.GetSize();
  1184. }
  1185. }
  1186. if (m_dTotalColumns != 0)
  1187. {
  1188. m_bAppend = true;
  1189. }
  1190. return true;
  1191. }
  1192. delete File;
  1193. }
  1194. }
  1195. catch(...)
  1196. {
  1197. }
  1198. m_sLastError = "Error in opening filen";
  1199. return false;
  1200. }
  1201. }
  1202. // Convert Excel column in alphabet into column number
  1203. short CSpreadSheet::CalculateColumnNumber(CString column, bool Auto)
  1204. {
  1205. if (Auto)
  1206. {
  1207. int firstLetter, secondLetter;
  1208. column.MakeUpper();
  1209. if (column.GetLength() == 1)
  1210. {
  1211. firstLetter = column.GetAt(0);
  1212. return (firstLetter - 65 + 1); // 65 is A in ascii
  1213. }
  1214. else if (column.GetLength() == 2)
  1215. {
  1216. firstLetter = column.GetAt(0);
  1217. secondLetter = column.GetAt(1);
  1218. return ((firstLetter - 65 + 1)*26 + (secondLetter - 65 + 1)); // 65 is A in ascii
  1219. }
  1220. }
  1221. // Check if it is a valid field name
  1222. for (int i = 0; i < m_aFieldNames.GetSize(); i++)
  1223. {
  1224. if (!column.Compare(m_aFieldNames.GetAt(i)))
  1225. {
  1226. return (i + 1);
  1227. }
  1228. }
  1229. m_sLastError = "Invalid field name or column alphabetn";
  1230. return 0;
  1231. }
  1232. // Get the name of the Excel-ODBC driver
  1233. void CSpreadSheet::GetExcelDriver()
  1234. {
  1235. char szBuf[2001];
  1236. WORD cbBufMax = 2000;
  1237. WORD cbBufOut;
  1238. char *pszBuf = szBuf;
  1239. // Get the names of the installed drivers ("odbcinst.h" has to be included )
  1240. if(!SQLGetInstalledDrivers(szBuf,cbBufMax,& cbBufOut))
  1241. {
  1242. m_sExcelDriver = "";
  1243. }
  1244. // Search for the driver...
  1245. do
  1246. {
  1247. if( strstr( pszBuf, "Excel" ) != 0 )
  1248. {
  1249. // Found !
  1250. m_sExcelDriver = CString( pszBuf );
  1251. break;
  1252. }
  1253. pszBuf = strchr( pszBuf, '' ) + 1;
  1254. }
  1255. while( pszBuf[1] != '' );
  1256. }
  1257. #endif