Чтение файлов 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;
}