ODBC可以操作Excel,給程序猿們帶來了方便 ,但是其中的坑真多啊,說起來真是淚,記錄下來,也幫助有需要的人不掉坑里。
1.首先,驅動有兩個,
?{Microsoft Excel Driver (*.xls)}和
?{Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)}
第一個是ODBCJT32.DLL,支持低版本的office;第二個是ACEODBC.DLL(The ODBC Excel driver (ACE)),支持高版本的Office。
建議使用高版本的驅動,如果windows沒有帶高版本的驅動,可以在這里下載:
http://www.microsoft.com/en-us/download/details.aspx?id=13255(Microsoft Access Database Engine 2010 Redistributable)這是2010版,也可以在上面找2016版下載。
2.ODBC DSN,一般格式如下:
DRIVER={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};READONLY=FALSE;DBQ=xx.xls
好多文檔里說還有MaxScanRows?,IMIX,HDR等選項,這方面?的資料比較少,但是好像都不起作用,
3.文件名
這就是一個大坑了,使用英文名,完全沒有問題,但是有一天你突然要打開一個中文文件,可能就會發現出問題了。why?這個可能與操作系統有關,我win 10 64位,系統默認字符集是utf-8,所以DSN要轉換成utf8才能正確打開文件。
4.表
表有三種:
1)自建表,Select * from MyNamedRange
2)sheet,Select * from [MyWorksheet$]
3)range ,?Select * from [MyWorksheet$C3:M8]
操作表的時候要注意了
5.獲取文件里面的所有表
由于excel不是專門的數據庫,里面沒有存放一些常規數據庫的信息,所以沒有方法能直接獲取到所有的表,只有調用ODBC?API才能實現,大概是下面這樣實現:
std::vector<string> TableList;
//excel get tables -->
#define? TABLE_NAME_LENGTH? 100?
SQLHDBC hdbc;
HSTMT hStmt;
int ret = -1;
UCHAR? ? ? szName[256] = { 0 };
SDWORD? ? cbName;
ret = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hStmt);
//? 獲取表信息(返回一個數據表)?
ret = SQLTables(hStmt,
NULL, SQL_NTS, //(SQLCHAR*)SQL_ALL_CATALOGS
NULL, SQL_NTS,
NULL, SQL_NTS,
NULL, SQL_NTS);//(SQLCHAR*)"SYSTEM TABLE"
if (ret == SQL_ERROR)
{
SQLFreeStmt(hStmt, SQL_CLOSE);
//database.Close();
if (ret == SQL_INVALID_HANDLE)
{
//return? false;
}
//return? false;
}
while (1)
{
//取數據到緩沖區
ret = SQLFetch(hStmt);
if (ret == SQL_NO_DATA_FOUND)
break;
//取某一列數據(第3列為表名,其他還有表屬性、數據庫名等)?
ret = SQLGetData(hStmt, 3, SQL_C_CHAR, szName, TABLE_NAME_LENGTH, &cbName);
OutputDebugStringA((char*)szName);
OutputDebugStringA("\t");
TableList.push_back( std::string((char*)szName) );
ret = SQLGetData(hStmt, 4, SQL_C_CHAR, szName, TABLE_NAME_LENGTH, &cbName);
OutputDebugStringA((char*)szName);
OutputDebugStringA("\n");
}
//? 釋放句柄?
SQLFreeStmt(hStmt, SQL_CLOSE);
6.混合字段,這個是最大的坑
對于excel有些列是混合字段,如既有文本又有數字,這個時間odbc就會凌亂了,順便也會把你帶崩潰
由于excel沒有專門存儲列類型的結構,所以odbc驅動是不知道你這個列是什么類型的,MaxScanRows就出廠的,這個值默認是8,意思就是驅動要掃描8行,確定這個列是什么類型。這就比較麻煩了,1.混合字段只掃8行根本看不出哪個占多,就是確定了一個類型,比如文本,你讀純數字的時候,讀出來的都是空值。。。。
這個只有強制在excel中把這一列設成文本,可以解決這個問題。。。
當然,實際情況中坑可能還要多,希望能有所幫助。