2016-10-04 40 views
0

我需要從ms sql表中放入並檢索大的二進制數據。如何使用WinApi從MS SQL表檢索大型二進制數據?

把數據我用ifstream和SQLPutData。這裏是我的代碼把數據(沒有錯誤檢查和分配一些手柄):

char file[MAX_PATH] = ""; 
    strcpy(file, argv[2]); 
    ifstream f(file, ios::binary | ios::ate); 
    size_t sz = f.tellg(); 
    f.seekg(0, ios::beg); 
    char *buf = new char[sz]; 
    char *ptr = buf; 
    f.read(ptr, sz); 
    f.close(); 
SQLLEN lbytes, cbBinarySize; 
    PTR pParamID; 
    lbytes = (SDWORD) sz; 
    cbBinarySize = SQL_LEN_DATA_AT_EXEC(lbytes); 

char SQL[512] = "INSERT INTO bindata (filename, binData) VALUES ('"; 
    strcat(SQL, file); 
    strcat(SQL, "', ?)"); 

ret = SQLPrepare(stmt, (SQLCHAR *) SQL, SQL_NTS); 
SQLSMALLINT dataType, decDigits, nullable; 
    SQLUINTEGER paramsize; 
ret = SQLDescribeParam(stmt, 1, &dataType, &paramsize, &decDigits, &nullable); 
    ret = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY, dataType, paramsize, 0, (VOID *)1, 0, &cbBinarySize); 

    ret = SQLExecDirect(stmt, (SQLCHAR *) SQL, SQL_NTS); 

    if (ret != SQL_NEED_DATA && ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) return ret; 

    ret = SQLParamData(stmt, &pParamID); 
    if (ret == SQL_NEED_DATA) { 
     while (lbytes > 5000) { 

      ret = SQLPutData(stmt, (SQLCHAR *)ptr, 5000); 
      lbytes -= 5000; 
      ptr += 5000; 
     } 

     ret = SQLPutData(stmt, ptr, lbytes); 


     ret = SQLParamData(stmt, &pParamID); 
     if (ret != SQL_SUCCESS) return ret; 

} 
SQLFreeHandle(SQL_HANDLE_STMT, stmt); 
delete[] ptr; 
delete[] buf; 

這工作對我很好,我在我的VARBINARY(MAX)表中的字段的二進制數據。現在我想從那裏獲取這些數據。這是我試圖做的(我檢查了MSDN文章https://msdn.microsoft.com/en-us/library/ms811006.aspx):

unsigned char* data = new unsigned char[2500000]; 
    SQLINTEGER cbFdata = SQL_NTS; 

    SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt); 
    ret = SQLExecDirect(stmt, (SQLCHAR *) "SELECT binData FROM bindata WHERE filename='AgentCPP.exe'", SQL_NTS); 
    if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) return ret; 

    ret = SQLFetch(stmt); 

    do { 

     ret = SQLGetData(stmt, 1, SQL_C_BINARY, data, 5000, &cbFdata); 

    } while (ret != SQL_NO_DATA_FOUND); 


    SQLFreeHandle(SQL_HANDLE_STMT, stmt); 

而不是包含我的數據的數組,我得到一些垃圾,這可能只是我的數據的一部分。我究竟做錯了什麼? 如果我使用的是.Net,我可能會使用某種byte []數組,或者某種東西,但是在這裏我不能。你能幫我麼?

UPD。只是試圖用C#來做,而我花了大約3分鐘和十幾行代碼。只是爲了顯示什麼結果,我試着讓 - 此代碼創建一個從二進制數據,這是從這個問題放進數據庫通過我的代碼第一塊完全正常的工作exe文件:

OdbcCommand com = new OdbcCommand(@"SELECT binData FROM bindata WHERE filename='AgentCPP.exe'", con); 
     com.Connection = con; 
     OdbcDataReader reader = com.ExecuteReader(); 

     if (reader.Read()) 
      binData = (byte[]) reader.GetValue(0); 

     reader.Dispose(); 
     com.Dispose(); 
     con.Close(); 

     FileStream fs = new FileStream(@"agent.exe", FileMode.Create, FileAccess.Write); 
     fs.Write(binData, 0, binData.Length); 
     fs.Close(); 

哪有我使用c winapi實現相同?

回答

1

好的,我似乎忘記了我的代碼中出了什麼問題。首先,我必須檢索數據的實際長度,而不是僅使用2500000的近似大小的數組,所以起初我使用假指針來獲取數據的大小,然後使用std :: vector。 其次,我把5000放入SQLGetData作爲我的數據的「一部分」,這是錯誤的,我需要使用實際大小的數據。所以這裏是代碼,這對我來說工作很好:

SQLINTEGER cbSize = SQL_NTS; 

    ret = SQLExecDirect(stmt, (SQLCHAR *) "SELECT binData FROM bindata WHERE filename='AgentCPP.exe'", SQL_NTS); 
    if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) return ret; 

    ret = SQLFetch(stmt); 

    char *ptr = new char[1]; 
    if ((ret = SQLGetData(stmt, 1, SQL_C_BINARY, ptr, 0, &cbSize) != SQL_NO_DATA)) 
    { 

     vector<char> vec(cbSize); 
     SQLGetData(stmt, 1, SQL_C_BINARY, &vec[0], cbSize, &cbSize); 
     ofstream fout; 
     fout.open("test.exe", ios::binary); 
     fout.write(&vec[0], cbSize); 
     fout.close(); 
     vec.clear(); 
     } 
    delete[] ptr; 
相關問題