SpreadSheet.cpp 28 KB

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