Сообщений 7    Оценка 10        Оценить  
Система Orphus

Кэш для Excel

Автор: Анисимов Антон
Опубликовано: 11.03.2003
Исправлено: 13.03.2005
Версия текста: 1.0
Для чего нужно?
Почему DLL?
Описание функций
Пример
Как это устроено
Примечания

Для чего нужно?

В одно время у меня возникла необходимость в общении с Excel2000, при чем, объемы данных должны были проходить большие, что привело к появлению этой DLL-ки. При открытии файла все данные, находящиеся в нем загружаются в динамический строковый кэш (при нынешних объемах памяти это не так много) и потом можно работать с ним. К сожалению, форматирование не кэшируется, да и задач таких не ставилось. В результате тестирования программа, работающая с Excel с помощью OLE (COM тоже пробовали) втискивала туда 15000 ячеек за 50 секунд, а через эту DLL-ку за 3. Разница, как говорится, на лице :).

В дополнение к этому, система IntelliSense в BCB 5.0, и без того достаточно медленная, при подключении ATL через директиву #include совсем умирает. Именно поэтому в DLL используются не все функции Excel, а те, которые мне пригодились в реальной работе.

Опять же, работать с числовыми индексами удобнее, чем с адресами ячеек, по крайней мере, мне так кажется.

Почему DLL?

При работе с разными компиляторами возникают проблемы, например, с lib-ы от VC 6.0 в BCB 5.0 не подключаются, а исходный код каждый раз менять (хотя бы stdafx.h выкидывать, или вставлять обратно), нудно, а так - подключил, и работай.

Описание функций

XlSetColor (char *Cells,XlColorIndex Color);Установка цвета ячеек
XlSetCellsBorder (char *Cells, bool H, bool V, bool R, bool L, bool T, bool B, XlLineStyle style=xlContinuous, XlBorderWeight Width=xlThin,XlColorIndex Color=xlColorIndexAutomatic);Установка границы ячеек
XlRunExcel();Запуск Excel
XlNewBook();Создать новую книгу, выбрать первый лист
XlOpenBook( const char * FileName);Открыть книгу, выбрать первый лист
XlSheetSelect(short Index);Выбрать лист
XlCommit();Подтвердить изменения
XlSetMinMaxInt(const int Rows,const int Cols);Установить область кэширования
char * XlGetMinMax();Получить область кэширования
void XlSetMinMax ( const char * Val);Установить диапазон ячеек для кэширования
const char * XlGetCell(int Row, int Col);Получить значение ячейки
void XlPutCell(int Row, int Col, const char * Val);Установить значение ячейки
XlSave ();Сохранить
XlSaveAs (const char *Val);Сохранить как
XlClose ();Закрыть текущую книгу
XlCloseExcel ();Закрыть Excel
XlSetParams(char* Cells, XlHAlign HorAl=xlHAlignGeneral, XlVAlign VerAl=xlVAlignBottom, bool Warp=false, int Orient=0,bool Ident=false,bool Shrink=false, bool Merge=false);Установить параметры ячейки
XlSetColWidth(char *Col,int Width);Установить ширину столбца
XlSetRowHeight(char *Row,int Height);Установить высоту строки
XlDragVPageBreak(XlDirection Dir=xlToRight , long RegionIdx=1);Установка горизонтальной границы листа
Xlbool SetView(XlWindowView View=xlPageBreakPreview);Установка вида
XlSetPageOrient(XlPageOrientation Orient=xlLandscape);Установка ориентации листа
XlSetColorIndex(char *Cells,long Color=6);Установка цвета
XlShow(bool Visibility);Видимость Excel
XlPrint(char *Printer);Печать текущей книги
LoadLib(char * Path), UnloadLib();Загрузка\выгрузка библиотеки

Везде, где не указано явно – функции возвращают bool, true – если функция успешно завершена.

Пример

Пример собран на BCB 5.0 в виде консольного приложения, которое конвертирует любую понятную BDE таблицу в XLS без названий столбцов. Предусмотрена пакетная обработка с указанием в имени файла метасимволов «*» и «?». Далее следуют части кода программы, которые относятся к самой DLL. Естественно, что данная утилита будет работать только при наличии BDE, но к сожалению я не смог ее собрать без Runtime Libraries, так, что ей нужны еще и они.

LoadLib( "exceldll.dll" ); //Загружаем библиотеку из текущего каталога
XlRunExcel(); //Запускаем COM сервер
while ( !done )  //Цикл перебора файлов для преобразования
{
    XlNewBook(); //Создаем новую книгу
    int iRowCount = 1;

    while ( !pBDETable->Eof )  //Цикл прохода по всем записям исходной таблицы
    {
        for ( int i = 0;i < pBDETable->Fields->Count;i++ )  //Цикл прохода по всем столбцам
            //Записывем данных в кэш
            XlPutCell( iRowCount, i + 1, pBDETable->Fields->Fields[ i ] ->AsString.c_str() );

        pBDETable->Next();

        iRowCount++;
    }

    //…

    XlCommit();	 //Обновляем данные в книге из кэша
    XlSaveAs( m_FileName ); //Сохраняем книгу
    XlClose(); //Закрываем книгу
}

XlCloseExcel(); //Останавливаем COM сервер

UnloadLib(); //Выгружаем библиотеку

Как это устроено

Для кэширования используется динамический массив C2DstringArray – одномерный массив CStringArray, второе измерение которого, просто содрано с CArray, в остальном данная библиотека – обертка для Excel и ее можно использовать как пример работы с Excel. Собственно, вот две функции, которые этим занимаются:

extern "C" __declspec( dllexport ) BOOL Commit()
{
    if ( Running )
    {
        try
        {
            CString RgnStop, Temp;
            VARIANT v;
            long Mrow = Cache.GetRows(), Mcol = Cache.GetCols();
            div_t D = div( Mcol - 1, 26 );
            D.rem++;

            if ( D.quot == 0 )
                RgnStop = ( char ) ( D.rem + '@' );
            else
                RgnStop = D.quot ? NULL : ( char ) ( D.quot + '@' ) + \
                          D.rem ? NULL : ( char ) ( D.rem + '@' );

            Temp.Format( "%S%i", RgnStop, Mrow );

            long Idx[ 2 ];

            SAFEARRAYBOUND Bnd[ 2 ];

            Bnd[ 0 ].lLbound = 0;
            Bnd[ 1 ].lLbound = 0;
            Bnd[ 0 ].cElements = Cache.GetRows();
            Bnd[ 1 ].cElements = Cache.GetCols();

            COleSafeArray mTArray;

            mTArray.Create( VT_BSTR, 2, Bnd );

            VariantInit( &v );

            v.vt = VT_BSTR;

            //Перенос данных из кэша в промежуточный массив.
            for ( Idx[ 0 ] = 0;Idx[ 0 ] < ( long ) Bnd[ 0 ].cElements;Idx[ 0 ] ++ )
                for ( Idx[ 1 ] = 0;Idx[ 1 ] < ( long ) Bnd[ 1 ].cElements;Idx[ 1 ] ++ )
                {
                    v.bstrVal = Cache.Values[ Idx[ 0 ] ] [ Idx[ 1 ] ].AllocSysString();
                    mTArray.PutElement( Idx, v.bstrVal );
                    SysFreeString( v.bstrVal );
                }

            ( ( Range ) Sheet.GetRange( COleVariant( "A1" ), COleVariant( Temp ) ) ).SetValue( *mTArray ); //*Cache
            VariantClear( &v );
            //mTArray.Destroy();

        }
        catch ( ... )
        {
            return false;
        }

        return true;
    }
    else
        return false;
}

extern "C" __declspec( dllexport ) void PutCell( int Row, int Col, FAR char * Val )
{
    if ( Running )
    {
        CString S = Val;
        int t;

        //Удаляем все управляющие символы.
        while ( ( t = S.Find( ( char ) 0xd ) ) != -1 )
            S.Delete( t );

        while ( ( t = S.Find( ( char ) 0xa ) ) != -1 )
            S.Delete( t );

        while ( ( t = S.Find( ( char ) 0x9 ) ) != -1 )
            S.Delete( t );

        S.TrimLeft();

        S.TrimRight();

        Cache.Values[ Row ][ Col ] = S;
    }
}

Примечания

В каталоге Export лежат файлы для подключения. Проверено, что работают в VC 6.0, и BCB 5.0.

Для тех, у кого OfficeXP, может, помогут файлы из архива ExcelExports, хотя, сильно сомневаюсь. Нет в нем документированных tlb-шек, чтобы втянуть функции ATL, однако, собранная библиотека работает и с ним, кажется, и с Office 97 работала, но ручаться не буду.

При использовании функций печати необходимо давать время Excel-у напечатать, иначе программа валится с External Exception. Собственно, при работе с любым MS Office-компонентом надо делать небольшие паузы, чтобы до них доходило то, что от них требуется :). Кстати, не следует забывать, что Excel понимает только 512 символов на ячейку.

Библиотека использовалась при экспорте и печати больших объемов данных. Примеры, к сожалению, очень специфические, например, экспорт из ГИС семантических данных с предварительным пространственным анализом :), однако есть небольшая программка на BCB 5.0, которая печатает большое количество xls файлов, и дает возможность продлить жизнь принтеру – делает передышки на 10 минут: PrintXLS.zip.

Замечания и пожелания приветствуются. mailto:saddam@hotmail.ru


Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав.
    Сообщений 7    Оценка 10        Оценить