15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту




Чтение файлов Excel через ODBC.

Автор: Alexander Mikula

  • Скачать демонстрационный проект - 20 Kb

    После публикации статьи о том, как как создать Excel файл, многим очень захотелось узнать - а как же из такого файла можно считать данные. ОК, давайте разберёмся ...

    Что нам потребуется

    Чтобы приведённый ниже код заставить работать необходимо проделать следующее:

  • 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;
}

Подробности смотрите в демо-проекте (ReadExcelDlg.cpp)