在现代软件开发中,将图像文件存储到数据库中是一个常见的需求。虽然互联网上关于这方面的信息很多,但实际的C++示例却寥寥无几。本文将展示如何使用ADO技术将图像文件存储到数据库中,以及如何从数据库中检索这些文件。这个过程不仅适用于图像文件,也适用于Word、Excel等其他文件格式。
本文提供的示例包含了两种方法:一种是从数据库中检索图像文件,另一种是将图像文件存储到数据库中。第一种方法从数据库中检索数据,然后在临时目录中创建一个文件,并将数据写入该文件。参数strImageName是要创建的文件的名称,第二个参数是包含图像数据的ADO字段对象。
以下代码示例展示了如何从数据库中检索图像文件:
    CString CADOImageDBDlg::GetImageFromADO(CString strImageName, FieldPtr pField)
    {
        // 创建临时文件
        char tmpPath[_MAX_PATH+1];
        GetTempPath(_MAX_PATH, tmpPath);
        strImageName.Insert(0, tmpPath);
        CFile outFile(strImageName, CFile::modeCreate | CFile::modeWrite);
        // 辅助变量,用于检索图像数据
        unsigned char* lpData = NULL;
        long lngOffSet = 0;
        long lngSize = pField->ActualSize;
        const long ChunkSize = 50;
        _variant_t varChunk;
        UCHAR chData;
        HRESULT hr;
        long lBytesCopied = 0;
        lpData = new unsigned char[lngSize];
        // 从vararray中检索数据
        while (lngOffSet < lngSize)
        {
            try
            {
                // 从数据库中获取50字节大小的数据块
                varChunk = pField->GetChunk(ChunkSize);
                // 将数据块放入safe array
                for (long lIndex = 0; lIndex < ChunkSize - 1; lIndex++)
                {
                    hr = SafeArrayGetElement(varChunk.parray, &lIndex, &chData);
                    if (SUCCEEDED(hr))
                    {
                        ((UCHAR*)lpData)[lBytesCopied] = chData;
                        lBytesCopied++;
                    }
                    else
                        break;
                }
                lngOffSet += ChunkSize;
            }
            catch (_com_error &e)
            {
                dump_com_error(e);
                return FALSE;
            }
        }
        // 将数据写入文件
        LPSTR buffer = (LPSTR)GlobalLock(lpData);
        outFile.Write(lpData, lngSize);
        GlobalUnlock(lpData);
        delete lpData;
        // 返回完整路径的文件
        return strImageName;
    }
    
    bool CADOImageDBDlg::PutImageInADO(CString strFilePath, FieldPtr pFileData)
    {
        // 打开文件
        CFile fileImage;
        CFileStatus fileStatus;
        fileImage.Open(strFilePath, CFile::modeRead);
        fileImage.GetStatus(fileStatus);
        // 分配内存以存储数据
        ULONG nBytes = (ULONG)fileStatus.m_size;
        HGLOBAL hGlobal = GlobalAlloc(GPTR, nBytes);
        LPVOID lpData = GlobalLock(hGlobal);
        // 将数据放入文件
        fileImage.Read(lpData, nBytes);
        HRESULT hr;
        _variant_t varChunk;
        long lngOffset = 0;
        UCHAR chData;
        SAFEARRAY FAR *psa = NULL;
        SAFEARRAYBOUND rgsabound[1];
        try
        {
            // 创建safe array以存储字节数组
            rgsabound[0].lLbound = 0;
            rgsabound[0].cElements = nBytes;
            psa = SafeArrayCreate(VT_UI1, 1, rgsabound);
            while (lngOffset < (long)nBytes)
            {
                chData = ((UCHAR*)lpData)[lngOffset];
                hr = SafeArrayPutElement(psa, &lngOffset, &chData);
                if (hr != S_OK)
                    return false;
                lngOffset++;
            }
            lngOffset = 0;
            // 将safe array分配给一个变量
            varChunk.vt = VT_ARRAY | VT_UI1;
            varChunk.parray = psa;
            hr = pFileData->AppendChunk(varChunk);
            if (hr != S_OK)
                return false;
        }
        catch (_com_error &e)
        {
            dump_com_error(e);
            return FALSE;
        }
        // 释放内存
        GlobalUnlock(lpData);
        return true;
    }
    
为了显示图像,创建了一个类,该类封装了freeimage库。