Чтение файлов Excel через ODBC
Что нам потребуется
Чтобы приведённый ниже код заставить работать необходимо проделать следующее:
- include <afxdb.h>
- include <odbcinst.h>
- инсталлировать ODBC-драйвер под названием "MICROSOFT EXCEL DRIVER (*.XLS)" (или что-то вроде этого)
- У Вас должен быть установлен Администратор (Admin) ODBC версии 3.5 или выше
Недостатки
Использование псевдо DSN работает только с ODBC Администратором версии 3.51 и выше.
Использование класса CRecordset напрямую (без наследования) позволяет только считывать. Любые попытки изменить данные в базе приведут к отказу в доступе. Если Вам всё-таки надо произвести такую операцию, то прийдётся использовать CRecordset обычным путём. Другой недостаток состоит в том, что большой по объёму CRecordset существенно замедляет производительность. Решение этого недостатка заключается в использовании класса CSQLDirect находящегося в http://www.codeguru.com/mfc_database/direct_sql_with_odbc.shtml.
Исходный код
// Запрос файла Excel
void CReadExcelDlg::OnButton1()
{
CDatabase database;
CString sSql;
CString sItem1, sItem2;
CString sDriver;
CString sDsn;
CString sFile = "ReadExcel.xls"; // имя файла. также можно использовать
// что-то вроде C:\\Sheets\\WhatDoIKnow.xls
// Очищаем содержимое listbox
m_ctrlList.ResetContent();
// Ищем имя драйвера Excel. Это необходимо,
// потому что Microsoft имеет особенность использовать
// специфицеские имена типа "Microsoft Excel Driver (*.xls)" вместо
// "Microsoft Excel Treiber (*.xls)"
sDriver = GetExcelDriver();
if (sDriver.IsEmpty())
{
// Не получается найти этот драйвер!
AfxMessageBox("No Excel ODBC driver found");
return;
}
// Создаём псевдо DSN, включая имя драйвера и файла Excel
// теперь нам не понадобится иметь явный DSN, установленный в
// нашего Администратора ODBC
sDsn.Format("ODBC;DRIVER={%s};DSN='';DBQ=%s", sDriver, sFile);
TRY
{
// Открываем базу данных, используя предварительно созданный
// псевдо DSN
database.Open(NULL, false, false, sDsn);
// Распределяем записи
CRecordset recset(&database);
// Конструируем строку SQL запроса
// Заполните имена секций данных в Excel таблице, используя
// "Insert->Names"(Вставка->Имя), чтобы можно было работать данными
// как с таблицей в реальной базе данных. В Excel файле так же
// может содержаться более одной таблицы.
sSql = "SELECT field_1, field_2 "
"FROM demo_table "
"ORDER BY field_1";
// Выполняем данный запрос (косвенно открывая recordset)
recset.Open(CRecordset::forwardOnly, sSql, CRecordset::readOnly);
// получаем результаты
while (!recset.IsEOF())
{
// читаем строку результата
recset.GetFieldValue("field_1", sItem1);
recset.GetFieldValue("field_2", sItem2);
// Вставляем результат в список
m_ctrlList.AddString(sItem1 + " --> "+sItem2);
// Skip to the next resultline
recset.MoveNext();
}
// Закрываем базу данных
database.Close();
}
CATCH(CDBException, e)
{
// Открытие базы данных вызвало исключение, проще говоря ошибку...
AfxMessageBox("Database error: " + e->m_strError);
}
END_CATCH;
}
// Получаем имя Excel-ODBC драйвера
CString CReadExcelDlg::GetExcelDriver()
{
char szBuf[2001];
WORD cbBufMax = 2000;
WORD cbBufOut;
char *pszBuf = szBuf;
CString sDriver;
// Получаем имена проинсталлированных драйверов
// ("odbcinst.h" должен быть включён в проект )
if (!SQLGetInstalledDrivers(szBuf, cbBufMax, &cbBufOut))
return "";
// Ищем драйвер...
do
{
if (strstr(pszBuf, "Excel") != 0)
{
// Нашли !
sDriver = CString(pszBuf);
break;
}
pszBuf = strchr(pszBuf, '\0') + 1;
}
while (pszBuf[1] != '\0');
return sDriver;
}