пятница, 22 мая 2009 г.

конвертер из csv(txt/text) в dbase / csv to dbase file converter)

<[CDATA[O F F T O P

Прошло довольно много лет с тех времен, когда я ну прямо-таки "ИЗЗоВСЕХсИЛЛ" самостоятельно учил WINAPI/WTL/ATL/STL/Boost и т.д, короче учился программировать на C++ под Win32. В те дни я ваще понять не мог нафига нужна Java, если клиентское приложение грузится дольше Windows... В общем по сути это было время когда я о серверах вообще не задумывался, я думал только о том как угодить хотя бы какому-нибудь пользователю с "суперидейным" "десктопным" "велосипедом".
Говоря короче - я только и занимался, что писал крохотные приложения на Visual C++ (в основном GUI)... Данное "введение" я веду к тому, что моя мечта пару недель назад осуществилась и не так давно мне наконец-то предоставилась возможность написать еще одну "кроху", причем теоретически полезную не только мне, но и кому-то еще.   

]]>

Описание приложения:

Эта программа предназначена для загрузки данных из текстового фала в файлы базы данных dbase.

Достоинства:
  1. Полный исходник
  2. Достаточно подробная настройка (через параметры коммандной строки можно передавать вплоть до строки с настройками драйвера и др.)
Недостатки:
  1. программа писалась примерно столько же времени сколько я пишу этот пост, поэтому, в частности ей не хватает токования ошибок ODBC.

Исходный код:
  1. #include "stdafx.h"
  2. //#undef _UNICODE
  3. #include <windows.h>
  4. #include <shlwapi.h>
  5. /* we'll using standart C++ library */
  6. #include <iostream>
  7. #include <fstream>
  8.  
  9. #include <tchar.h>
  10. #include <sqltypes.h>
  11. #include <sqlext.h>
  12. #include <sql.h>
  13.  
  14. #include <odbcinst.h>
  15. #pragma comment(lib, "odbccp32")
  16. #pragma comment(lib, "shlwapi")
  17.  
  18. // execution options
  19.  
  20. #define EXEC_SQL
  21. //#define DONT_CREATE_DSN
  22. //#define DONT_REMOVE_DSN
  23.  
  24. using namespace std;
  25.  
  26. enum SQL_DATA_TYPES { SDT_VARCHAR, SDT_NUMBER, SDT_DATE };
  27.  
  28. #ifdef _UNICODE
  29. #define mcout wcout
  30. #define mstring wstring
  31. #else
  32. #define mcout cout
  33. #define mstring string
  34. #endif
  35.  
  36. #define N_TYPE _T("type")
  37. //#define SZ_NAME _T("name")
  38. #define N_SIZE _T("size")
  39. #define N_COLUMN _T("order")
  40. #define SZ_T_COPYRIGHT_INFO _T("CSV(text) to DBF universal converter / (c) stash, 2009")
  41. #define TABLE_NAME "export01\0"
  42. #define DELETE_DATA_QUERY "DELETE FROM "TABLE_NAME
  43.  
  44. //#define szUser _T("")
  45. //#define szPass _T("")
  46.  
  47. #define LPRECINFO RECINFO*
  48.  
  49. #define T_DEFAULT_TABLE_NAME    _T("export01")
  50. #define T_DEFAULT_OUTPUT_NAME    _T("export01.dbf")
  51. #define T_DEFAULT_DSN            _T("text2dbase3tmp")
  52. #define T_DEFAULT_DRV            _T("Microsoft dBase Driver (*.dbf)")
  53. #define T_DEFAULT_DSN_PARAMS    _T("DSN=%WORKDSN%;Fil=dBase III;DriverID=21;DefaultDir=%TARGETDIR%")
  54. #define T_WORKDIR                _T("%WORKDIR%")
  55. #define T_TARGETDIR                _T("%TARGETDIR%")
  56.  
  57. #define T_WORKFILE                _T("%WORKFILE%")
  58. #define T_WORKDSN                _T("%WORKDSN%")
  59. #define T_TABLENAME                _T("%TABLENAME%")
  60. #define T_DEFAULT_SKIP_BEFORE    0
  61. #define T_DEFAULT_SKIP_AFTER    2
  62.  
  63. #define N_INIT_ERROR            -1
  64. #define SQL_ERROR_HANDLE_ENV    -2
  65. #define SQL_ERROR_HANDLE_DBC    -3
  66. #define SQL_DSN_CONFIG_ERROR    -4
  67. #define SQL_ERROR_HANDLE_STMT    -5
  68. #define IO_CANNOT_ALLOC_MEMORY    -6
  69. #define IO_CANNOT_INPUT_STREAM    -7
  70. #define IO_FILE_NOT_FOUND        -8
  71. #define N_ENOUGH_PARAMETERS        -9
  72. #define WRONG_ARGS                -10
  73.  
  74. #ifdef _DEBUG
  75. #define DEVELOPPER_STAGE // additional debug option
  76. #endif
  77.  
  78. #define RECINFO_DEFAULT_SIZE      0x000000FF
  79. #define RECINFO_DEFAULT_ORDER     0x00000001
  80. #define RECINFO_DEFAULT_SQL_TYPE  SDT_VARCHAR
  81. #define RECINFO_DEFAULT_SQL_TYPE_INT          1


  82. struct RECINFO
  83. {
  84.     SQL_DATA_TYPES m_nSqlDataType;
  85.     int m_nColumn, m_nLength;
  86.     std::mstring m_name; // TCHAR
  87.     std::string m_value; // char only
  88.     void setValue(char *val) {
  89.         //cout << " source: " << val << endl;
  90.  
  91.         for (size_t i=0; i<strlen(val); i++)
  92.             if (val[i]=='\''/* || val[i]=='\x0A'*/)
  93.                 val[i]='"';
  94.  
  95.         //cout << " after replacements: [[[ " << val << "]]]" << endl;
  96.         m_value = val;
  97.         //m_value.replace("
  98.     }
  99.     void set(  SQL_DATA_TYPES  nType      = RECINFO_DEFAULT_SQL_TYPE,
  100.         int                     data_size  = RECINFO_DEFAULT_SIZE,
  101.         int                     nColumnNum = 1,
  102.         TCHAR*                 strName          = _T("ID")) {
  103.  
  104.             m_nSqlDataType = nType;
  105.             m_nColumn = nColumnNum;
  106.             m_name = strName;
  107.             m_nLength = data_size;
  108.     }
  109.     RECINFO(int nType = RECINFO_DEFAULT_SQL_TYPE_INT, int data_size = RECINFO_DEFAULT_SIZE, int nColumnNum = 1, TCHAR* strName = _T("ID")) {
  110.         SQL_DATA_TYPES sql_data_type_fellow = SDT_VARCHAR;
  111.         switch(nType) {
  112. case 0:
  113. case 2:
  114.     sql_data_type_fellow = SDT_NUMBER;
  115.     break;
  116. case 3:
  117.     sql_data_type_fellow = SDT_DATE;
  118.     break;
  119.         }
  120.         set(sql_data_type_fellow, data_size, nColumnNum, strName);
  121.     }
  122.     /* RECINFO ( SQL_DATA_TYPES nType = SDT_VARCHAR,
  123.     int      data_size = RECINFO_DEFAULT_SIZE,
  124.     int      nColumnNum = RECINFO_DEFAULT_ORDER,
  125.     TCHAR*    strName = _T("ID")) {
  126.     set(nType, data_size, nColumnNum, strName);
  127.     }; */
  128.     void check() {
  129.         mcout << _T("Column N") << m_nColumn << _T(" (\"") << m_name.c_str() << _T("\"), length=") << m_nLength << endl;
  130.     }
  131.     //~RECINFO() { name=delete string(_T("")); }
  132. };
  133.  
  134. struct APPLICATION {
  135.  
  136. protected:
  137.     int      m_nTOTAL_COLUMNS_DONT_TRY_CHANGE_THIS_VALUE; // total readed columns
  138.     LPRECINFO m_lpRecinfo[1024]; // all columns
  139.     SQLHENV  m_henv;
  140.     SQLHDBC  m_hdbc;
  141.     SQLHANDLE m_hstmt;
  142.     int      m_nTotalRecordSize;
  143. public:
  144.     int      m_nErrorCode;
  145.     mstring  m_strError;
  146.     mstring  m_strDSN, m_strLogin, m_strPassword;
  147.     mstring  m_strIniFile;
  148.     mstring     m_strEmptyDbf;
  149.     mstring     m_strTargetFilename;
  150.     //mstring m_strDSNName;
  151.     mstring  m_strDSNDriver;
  152.     mstring  m_strDSNParams;
  153.     mstring  m_strSourceProcFile;
  154.     mstring  m_strTableName;
  155.     mstring  m_strOutputDirectory;
  156.     mstring  m_strSourceDirectory;
  157.  
  158.         int     m_nSkipBytesAfterEachRecord;
  159.         int     m_nSkipBytesBeforeEachRecord;
  160.  
  161. // -- methods
  162.     int status() {
  163.         if (m_nErrorCode>=0)
  164.             return S_OK;
  165.         return E_FAIL;
  166.     }
  167.     APPLICATION(int c_argc, _TCHAR* c_argv[]) { /* default constructor was called */
  168.         m_nTOTAL_COLUMNS_DONT_TRY_CHANGE_THIS_VALUE = 0;
  169.         m_henv = NULL;
  170.         m_hdbc = NULL;
  171.         m_hstmt = NULL;
  172.         m_nErrorCode = 0;
  173.         if (c_argc < 2) {
  174.             ShowUsage();
  175.             setLastErrorIndex(_T("Not enough of application arguments"), N_ENOUGH_PARAMETERS);
  176.         }
  177.         else {
  178.             ReadCommandLine(c_argc, c_argv);
  179.         }
  180.     };
  181. private:
  182.     void setLastErrorIndex(TCHAR *szError, int lastErrorIndex = N_INIT_ERROR) {
  183.         m_strError = szError;
  184.         m_nErrorCode = lastErrorIndex;
  185.     }
  186. public:
  187.     int reportError(bool quitRightNow = true) {
  188.         mcout << _T("Error: ") << this->m_strError.c_str() << endl;
  189.         return m_nErrorCode;
  190.     }
  191.     bool ReadConfig( mstring str_inifile ) {
  192.         TCHAR* d = new TCHAR[0x7fff];
  193.         memset(d, 0, sizeof(d));
  194.         DWORD dw = GetPrivateProfileSectionNames(d, 0x7fff, str_inifile.c_str());
  195.         if (dw < 5) {
  196.             setLastErrorIndex( _T("too short or empty ini-file -> application will now quit, bye-bye") );
  197.             return false;
  198.         }
  199.         bool quit = false;
  200.         int counter = 0;
  201.         int nColumn = 0;
  202.         m_nTotalRecordSize = 0;
  203.         while (!quit && counter < (int)dw) {
  204.             mcout << "adding column = " << d+counter << endl;
  205.             m_lpRecinfo[nColumn++] = new RECINFO( GetPrivateProfileInt(d+counter, N_TYPE, 1, str_inifile.c_str()),
  206.                 GetPrivateProfileInt(d+counter, N_SIZE, 255, str_inifile.c_str()),
  207.                 GetPrivateProfileInt(d+counter, N_COLUMN, 1, str_inifile.c_str()),
  208.                 d+counter);
  209.             m_nTotalRecordSize += GetPrivateProfileInt(d+counter, N_SIZE, 255, str_inifile.c_str());
  210.             //lpRecinfo[nColumn++] = new ;
  211.             //memset(e,0,sizeof(e));
  212.             counter += lstrlen(d+counter)+1;
  213.         }
  214.         /*final*/m_nTOTAL_COLUMNS_DONT_TRY_CHANGE_THIS_VALUE = nColumn;
  215.         delete d;
  216.         return true;
  217.     }
  218.  
  219.     bool InitODBC(TCHAR *szDSN = NULL, TCHAR *szLogin = _T(""), TCHAR *szPass = _T(""))
  220.     {
  221.         if (szDSN!=NULL)
  222.             m_strDSN = szDSN;
  223.         m_strLogin = szLogin;
  224.         m_strPassword = szPass;
  225.  
  226.         if (SQLAllocHandle(SQL_HANDLE_ENV, NULL, &m_henv) == SQL_ERROR) { // Alloc env handle
  227.             setLastErrorIndex(_T("AllocHandle on ENV failed."), SQL_ERROR_HANDLE_ENV);
  228.             return false;
  229.         }
  230.  
  231.         SQLSetEnvAttr(m_henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, SQL_IS_INTEGER);
  232.  
  233.         if (SQLAllocHandle(SQL_HANDLE_DBC, m_henv, &m_hdbc) == SQL_ERROR) {
  234.             setLastErrorIndex(_T("AllocHandle on DBC failed."), SQL_ERROR_HANDLE_DBC);
  235.             return false;
  236.         }
  237.         if ( SQLConnect(m_hdbc, (SQLTCHAR*)m_strDSN.c_str(), SQL_NTS,
  238.             (SQLTCHAR*)m_strLogin.c_str(), m_strLogin.length(), (SQLTCHAR*)m_strPassword.c_str(),
  239.             m_strLogin.length() ) == SQL_ERROR ) {
  240.                 setLastErrorIndex(_T("Connect to ODBC failed."), SQL_DSN_CONFIG_ERROR);
  241.                 return false;
  242.         }
  243.         if (::SQLAllocHandle(SQL_HANDLE_STMT, m_hdbc, &m_hstmt) == SQL_ERROR) { // Get a statement handle 
  244.             setLastErrorIndex(_T("AllocHandle on STMT failed."), SQL_ERROR_HANDLE_STMT);
  245.             return false;
  246.         }
  247.         return true;
  248.     }
  249.  
  250.     void construct_insert_query(TCHAR *output, int nMaxLength, LPRECINFO cols[], int length_r) {
  251.         memset(output, 0, nMaxLength*sizeof(TCHAR));
  252.         lstrcpy(output, _T("INSERT INTO "));
  253.         lstrcat(output, m_strTableName.c_str());
  254.         lstrcat(output, _T(" ("));
  255.         for (int i=0; i<length_r; i++) {
  256.             if (cols[i]->m_value.length()>0) {
  257.                 if (i) lstrcat(output, _T(","));
  258.                 output[lstrlen(output)] = _T('`');
  259.                 lstrcat(output, cols[i]->m_name.c_str());
  260.                 output[lstrlen(output)] = _T('`');
  261.             }
  262.         }
  263.         lstrcat(output, _T(") VALUES ("));
  264.         for (int i=0; i<length_r; i++) {
  265.             if (cols[i]->m_value.length()>0) {
  266.                 if (i) lstrcat(output, _T(","));
  267.                 if ( cols[i]->m_nSqlDataType != SDT_NUMBER)
  268.                     output[lstrlen(output)] = _T('\'');
  269.                 lstrcat(output, cols[i]->m_value.c_str());
  270.                 if ( cols[i]->m_nSqlDataType != SDT_NUMBER)
  271.                     output[lstrlen(output)] = _T('\'');
  272.             }
  273.         }
  274.         lstrcat(output, _T(")"));
  275.     }
  276.  
  277.     bool processSqlReturn( SQLRETURN ret, SQLHANDLE sql_handle)
  278.     {
  279.         bool is_it_success = false;
  280.  
  281.         if (sql_handle == NULL)
  282.             mcout << _T(" hstmt is NULL! ") << endl;
  283.  
  284.         if ( ret == 0 ) {
  285.             is_it_success = true;
  286.             mcout << _T("success!") << endl;
  287.         }
  288.         else
  289.             mcout << _T("failed, with return code: ") << ret << endl;
  290.         return is_it_success;
  291.     }
  292.     int getTotalCols() { return m_nTOTAL_COLUMNS_DONT_TRY_CHANGE_THIS_VALUE; }
  293.  
  294.     bool ProcessTextFile( const TCHAR* szFilename ) {
  295.         fstream ifile(szFilename, ios_base::in | ios_base::binary);
  296.         char *ibuff = new char[m_nTotalRecordSize];
  297.         char *obuff = new char[0x7fff];
  298.         char *buf  = new char[0x1000];
  299.         char *buf2  = new char[0x1000];
  300.         char trim[] = ("\x20\x09\0");
  301.  
  302.         if(!ifile.is_open()) {
  303.             setLastErrorIndex(_T("Cannot open input text stream"), IO_CANNOT_INPUT_STREAM);
  304.             return false;
  305.         }
  306.         if(!ibuff || !obuff || !buf) {
  307.             ifile.close();
  308.             setLastErrorIndex(_T("Cannot Allocate buffers"), IO_CANNOT_ALLOC_MEMORY);
  309.             return false;
  310.         }
  311.         int nOff = 0;
  312.         //cout << _T("Executing query: ") << DELETE_DATA_QUERY << endl;
  313.         //return 0;
  314.         //if (!processSqlReturn(SQLExecDirect(hstmt, (SQLCHAR*)DELETE_DATA_QUERY, SQL_NTS),hstmt))
  315.         //    reportError(_T("Cannot drop data from ")TABLE_NAME);
  316.  
  317.         while(!ifile.eof()) {
  318.             memset(ibuff, 0, m_nTotalRecordSize); // why? :-/
  319.             if (m_nSkipBytesBeforeEachRecord>0) {
  320.                 ifile.seekg( m_nSkipBytesBeforeEachRecord, ios_base::cur );
  321.                 if(ibuff[0] == 0 && ifile.eof()) break; // just exit from loop
  322.             }
  323.             ifile.read(ibuff, m_nTotalRecordSize);
  324.             if(ibuff[0] == 0 && ifile.eof()) break; // just exit from loop
  325.             if (m_nSkipBytesAfterEachRecord>0) {
  326.                 ifile.seekg( m_nSkipBytesAfterEachRecord, ios_base::cur );
  327.                 if(ibuff[0] == 0 && ifile.eof()) break; // just exit from loop
  328.             }
  329.             nOff = 0;
  330.             //mcout << _T("---[ RECORD ]---------------") << endl;
  331.             for (int j=0; j < getTotalCols(); j++) {
  332.                 memcpy(buf, ibuff+nOff, m_lpRecinfo[j]->m_nLength);
  333.                 buf[ m_lpRecinfo[j]->m_nLength - 1 ] = '\x0';
  334.                 StrTrimA(buf,trim);
  335.                 /* if ())
  336.                     cout << "Trimmed: " << buf << endl;
  337.                 else
  338.                     cout << "NOT Trimmed: " << buf << endl; */
  339.                 // for construct "insert" query
  340.                 /* if ( CharToOem( buf, buf2 ) ) {
  341.                     m_lpRecinfo[j]->setValue( buf2 );
  342.                     buf2[ m_lpRecinfo[j]->m_nLength ] = '\x0';
  343.                 }
  344.                 else { */
  345.                     m_lpRecinfo[j]->setValue( buf );
  346.                 //}
  347.                 nOff += m_lpRecinfo[j]->m_nLength;
  348.             }
  349.             construct_insert_query(obuff, 0x7fff, m_lpRecinfo, getTotalCols());
  350.             mcout << _T("executing query: \"") << obuff << _T("\"...");
  351. #ifdef EXEC_SQL
  352.             processSqlReturn( SQLExecDirect(m_hstmt, (SQLCHAR*)obuff, SQL_NTS), m_hstmt );
  353. #else
  354.             mcout << _T("execution skipped") << endl;
  355. #endif
  356.         }
  357.         ifile.close();
  358.         delete obuff;
  359.         delete ibuff;
  360.         delete buf;
  361.         delete buf2;
  362.         return true;
  363.     }
  364.     void FreeAllThatPossible() {
  365.         while (m_nTOTAL_COLUMNS_DONT_TRY_CHANGE_THIS_VALUE-->0)
  366.             delete m_lpRecinfo[m_nTOTAL_COLUMNS_DONT_TRY_CHANGE_THIS_VALUE];
  367.         /* odbc deinit */
  368.         if (m_hstmt != NULL)
  369.             SQLFreeHandle(SQL_HANDLE_STMT, m_hstmt);
  370.         if (m_hdbc != NULL) {
  371.             SQLDisconnect(m_hdbc);
  372.             SQLFreeHandle(SQL_HANDLE_DBC, m_hdbc);
  373.         }
  374.         if (m_henv != NULL)
  375.             SQLFreeHandle(SQL_HANDLE_ENV, m_henv);
  376.     }
  377.     ~APPLICATION() {
  378.         FreeAllThatPossible();
  379.         mcout << _T(" \\--> Application will now exit -> bye-bye") << endl;
  380.     }
  381. #define T_BY_DEFAULT_START _T(" (e.g. ")
  382. #define T_BY_DEFAULT_END _T(")")
  383. #define T_DBF_EXTENSION    _T(".dbf")
  384.     void ShowUsage()
  385.     {
  386.         mcout << _T(" Usage: text2dbase.exe input.text [output.dbf] [output table name]]") << endl
  387.              << _T("        [DSN [DSN driver] [DSN parameters] ") << endl << endl
  388.             << _T(" Where \"input.text\" is a name of input text file with data") << endl << endl
  389.             << _T(" Optional: ") << endl
  390.             << _T(" \x1A output.dbf - output dbase-filename") << T_BY_DEFAULT_START << T_DEFAULT_OUTPUT_NAME << T_BY_DEFAULT_END << endl
  391.             << _T(" \x1A output table - name of the output table, where we'll store values") << T_BY_DEFAULT_START << T_DEFAULT_TABLE_NAME << T_BY_DEFAULT_END << endl << endl
  392.             << _T(" \x1A DSN - windows ODBC data source name") << T_BY_DEFAULT_START << T_DEFAULT_DSN << T_BY_DEFAULT_END << endl
  393.             << _T(" \x1A DSN driver - windows ODBC driver name") << T_BY_DEFAULT_START << T_DEFAULT_DRV << T_BY_DEFAULT_END << endl
  394.             << _T(" \x1A DSN parameters - ODBC DSN parameters") << T_BY_DEFAULT_START << T_DEFAULT_DSN_PARAMS << T_BY_DEFAULT_END << endl
  395.             << _T("This application need ini-file, named csv2dbase.ini") << endl
  396.             << _T("with fields descriptions, formatted as examle below:") << endl
  397.             << _T("  [column_name]") << endl
  398.             << _T("  size = 32") << endl
  399.             << _T("  order = 3") << endl
  400.             << _T("  type = 1") << endl;
  401.     }
  402.     bool ReadCommandLine(int argc, _TCHAR* argv[])
  403.     {
  404.         TCHAR pathBuff[0xff];
  405.         memset(pathBuff, 0, sizeof(pathBuff));
  406.         GetModuleFileName(NULL, pathBuff, MAX_PATH);
  407.         m_strIniFile = pathBuff;
  408.         m_strEmptyDbf = m_strIniFile;
  409.  
  410.         m_strEmptyDbf[m_strEmptyDbf.length()-1] = _T('f');
  411.         m_strEmptyDbf[m_strEmptyDbf.length()-2] = _T('b');
  412.         m_strEmptyDbf[m_strEmptyDbf.length()-3] = _T('d');
  413.  
  414.         m_strIniFile[m_strIniFile.length()-1] = _T('i');
  415.         m_strIniFile[m_strIniFile.length()-2] = _T('n');
  416.         m_strIniFile[m_strIniFile.length()-3] = _T('i');
  417.  
  418.         m_strEmptyDbf += _T(".empty");
  419.  
  420.         while (lstrlen(pathBuff)>1 && pathBuff[lstrlen(pathBuff)-1]!=_T('\\'))
  421.             pathBuff[lstrlen(pathBuff)-1] = 0;
  422.         
  423.         m_strSourceDirectory = pathBuff;
  424.  
  425.         m_strTargetFilename = m_strSourceDirectory;
  426.         m_strSourceProcFile = m_strTargetFilename;
  427.  
  428.         string str;
  429.         
  430.  
  431.         m_strSourceProcFile += argv[1];
  432.  
  433.  
  434.         str = (argc > 2 ? argv[2] : T_DEFAULT_OUTPUT_NAME);
  435.         m_strTargetFilename      += str;
  436.         
  437.         memset(pathBuff, 0, sizeof(pathBuff));
  438.         lstrcpy(pathBuff, m_strTargetFilename.c_str());
  439.  
  440.         while (lstrlen(pathBuff)>1 && pathBuff[lstrlen(pathBuff)-1]!=_T('\\'))
  441.             pathBuff[lstrlen(pathBuff)-1] = 0; // uotput directory
  442.  
  443.         m_strOutputDirectory = pathBuff;
  444.  
  445.         if ( StrStr( str.c_str(), T_DBF_EXTENSION)==NULL ) {
  446.             setLastErrorIndex(_T("Wrong params"), WRONG_ARGS);
  447.             return false;
  448.         }
  449.  
  450.         m_strTableName = str.substr(0, str.length()-4);//m_strTargetFilename.substr(0, m_strTargetFilename.
  451.         if (argc > 3)
  452.             m_strTableName = argv[3];// : T_DEFAULT_TABLE_NAME);
  453.  
  454.         m_strDSN                = (argc > 4 ? argv[4] : T_DEFAULT_DSN);
  455.         m_strDSN += m_strTableName;
  456.         m_strDSNDriver         = (argc > 5 ? argv[5] : T_DEFAULT_DRV);
  457.         m_strDSNParams         = (argc > 6 ? argv[6] : T_DEFAULT_DSN_PARAMS);
  458.         
  459.  
  460.         m_nSkipBytesBeforeEachRecord = (argc > 6 ? atol(argv[7]) : T_DEFAULT_SKIP_BEFORE);
  461.         m_nSkipBytesAfterEachRecord = (argc > 7 ? atol(argv[8]) : T_DEFAULT_SKIP_AFTER);
  462.         
  463.  
  464.         // replacing %WORKDIR% template
  465.         if ( StrStr( m_strDSNParams.c_str(), T_WORKDIR)!=NULL )
  466.             m_strDSNParams.replace(m_strDSNParams.find( T_WORKDIR ), lstrlen(T_WORKDIR), m_strSourceDirectory);
  467.  
  468.         if ( StrStr( m_strDSNParams.c_str(), T_TARGETDIR)!=NULL )
  469.             m_strDSNParams.replace(m_strDSNParams.find( T_TARGETDIR ), lstrlen(T_TARGETDIR), m_strOutputDirectory);
  470.         
  471.         if ( StrStr( m_strDSNParams.c_str(), T_WORKDSN)!=NULL )
  472.             m_strDSNParams.replace(m_strDSNParams.find( T_WORKDSN ), lstrlen(T_WORKDSN), m_strDSN.c_str());
  473.         //if ( StrStr( m_strDSNParams.c_str(), T_TABLENAME)!=NULL )
  474.         //    m_strDSNParams.replace(m_strDSNParams.find( T_TABLENAME ), lstrlen(T_TABLENAME), m_strTableName.c_str());
  475.  
  476.         // and now we showing all our options "verbosely"
  477.         mcout << _T("Source file: ") << m_strSourceProcFile.c_str() << endl;
  478.         mcout << _T("Target file: ") << m_strTargetFilename.c_str() << endl;
  479.         mcout << _T("DSN: ") << m_strDSN.c_str() << endl;
  480.         mcout << _T("Driver: ") << m_strDSNDriver.c_str() << endl;
  481.         mcout << _T("Parameters: ") << m_strDSNParams.c_str() << endl;
  482.         mcout << _T("Table: ") << m_strTableName.c_str() << endl;
  483.  
  484.         if (!CopyFile(m_strEmptyDbf.c_str(), m_strTargetFilename.c_str(), false) ) {
  485.             mcout << _T("Source: ") << m_strEmptyDbf.c_str() << endl;
  486.             mcout << _T("Target: ") << m_strTargetFilename.c_str() << endl;
  487.             setLastErrorIndex(_T("Cannot create default file from empty file"), IO_FILE_NOT_FOUND);
  488.             return false;
  489.         }
  490.  
  491.         return true;
  492.     }
  493. };
  494.  
  495. int _tmain(int argc, _TCHAR* argv[])
  496. {
  497.     mcout << SZ_T_COPYRIGHT_INFO << endl;
  498.  
  499.     APPLICATION application(argc, argv);
  500.     if (application.status()!=S_OK) {
  501.         return application.reportError();
  502.         // application.m_nErrorCode;
  503.     }
  504.     
  505.     //return 0;
  506.  
  507.     // readCommandLine called
  508.     if (! SQLConfigDataSource(NULL, ODBC_ADD_DSN, application.m_strDSNDriver.c_str(), application.m_strDSNParams.c_str()) ) {
  509.         mcout << _T("Cannot create specified dsn") << endl;
  510.         return SQL_DSN_CONFIG_ERROR;
  511.     }
  512.  
  513.     mcout << _T("Loading ") << application.m_strIniFile.c_str() << _T("...") << endl;
  514.     
  515.     if (!application.ReadConfig( application.m_strIniFile ))
  516.         return application.reportError();
  517.  
  518.     if (!application.InitODBC( ))
  519.         return application.reportError();
  520.  
  521.     _ASSERT(argv[2]);
  522.     mcout << _T("\tProcessing: ") << application.m_strSourceProcFile.c_str() << endl;
  523.  
  524.     if (!application.ProcessTextFile( application.m_strSourceProcFile.c_str() ))
  525.         return application.reportError();
  526.  
  527.     //    exit(0);
  528. #ifndef DONT_REMOVE_DSN
  529.     if (! SQLConfigDataSource(NULL, ODBC_REMOVE_DSN, application.m_strDSNDriver.c_str(), application.m_strDSNParams.c_str()) )
  530.         mcout << _T("Cannot remove specified dsn") << endl;
  531. //    else
  532. //        mcout << _T("User's DSN successfully removed") << endl;
  533. #endif
  534. #ifdef DEVELOPPER_STAGE
  535.     wint_t ch;
  536.     cout << "done" << endl;
  537.     ch = NULL;
  538.     ch = getwchar();
  539. #endif
  540.  
  541.     //int retCode = application->m_nErrorCode;
  542.     return 0;}





Конечно, я не силен в С++, поэтому просьба особо критично не оценивать (и сразу извиняюсь за недостаток комментариев в исходном коде, как-нибудь обязательно займусь).

Кроме основного исполняемого-файла понадобятся файл инициализации, пустой файл таблицы, ну и конечно же сам текстовый файл с данными.

Для примера я выкладываю полный архив включающий все что только можно:
Скачать собранный проект (14 Кб) (включает в себя также скомпилированную программу)


добавлю еще пару замечаний к "проекту" :)

  1. из-за спешки я не отлаживал UNICODE-вариант компиляции

  2. если вы собираетесь компилировать ее свободным компилятором GNU или используя бесплатную IDE DevCpp ну или что-то подобное - у вас могут возникнуть сложности:

    • Если проект не работает с precompiled header - нунжо убрать включение файла "stdafx"

    • Если линковщик ругается на отсутствующую функцию main - переименуйте "_tmain" в "main"

    • Возможно, придется избавится от блоков директив "ifdef UNICODE..." и таким образом полностью избавиться от использования tchar/TCHAR/-типов wchar и макросов _T/TEXT/L и пр. Проще всего сменить их все char наверное :)