Больному уже лучше. Правда, он все еще в реанимации.
На что же уходит время в предыдущем варианте? Все просто! Львиная доля времени уходит на вызовы интерфейсов внешнего COM-сервера. И, не смотря на то, что мы используем ранее связывание с библиотекой типов, это так. Еще мой любимый классик (Калверт, знаете ли) писал о нетерпимости к вызовам интерфейсов внешних OLE-серверов в больших циклах. Как видите, классик прав.
Наша задача — избавиться от вызова Cell.Value в цикле. И это решаемо с помощью вариантных массивов. Вот так:
procedure TForm1.ToVarArray(ISheet: IxlWorksheet);
var Row, Column, i: integer;
IR1, IR2: IxlRange;
Arr: OLEVariant;
begin
Arr := VarArrayCreate([1, tblCust.RecordCount, 1, tblCust.Fields.Count], varVariant);
Row := 1;
tblCust.First;
while not tblCust.EOF do begin
Column := 1;
for i := 0 to tblCust.Fields.Count — 1 do begin
Arr[Row, Column] := FieldToVariant(tblCust.Fields[i]);
Inc(Column);
end;
Inc(Row);
tblCust.Next;
end;
IDispatch(IR1) := ISheet.Cells.Item[StartRow, StartColumn];
IDispatch(IR2) := ISheet.Cells.Item[StartRow + tblCust.RecordCount - 1,
StartColumn + tblCust.Fields.Count - 1];
ISheet.Range[IR1, IR2].Value := Arr;
end;
Здесь я использую вариантный массив Arr, который предварительно создается с размерами таблицы (количество записей на количество полей). Благо Microsoft построила очень четкую схему работы с вариантными массивами и интерфейсами, их «понимающими» (этим и пользуюсь). Из кода видно, что я по-прежнему прохожу всю таблицу, запоминая в элементах массива значения полей, полученных из вышеописанной функции FieldToVariant. Мы, ведь, снова используем варианты, и проблема строки «3/7″ остается. Последние три строки процедуры позволяют получить верхнюю левую и нижнюю правую ячейки области, в которую будут перенесены данные. А, затем, одним присваиванием в «Область.Value» я переношу данные из массива в ячейки этой области. Хорош способ, не правда ли? Код максимально прост. Время, полученное в ячейке A1 на порядок меньше. Правда, есть несколько проблем.
Главное, что бросилось бы в глаза опытного Delphi-разработчика, это создание массива в начале процедуры. Известно ли количество записей SQL-запроса после его открытия? Не всегда (FechAll). Хорошо, можно создать пустой массив и делать ему VarArrayRedim. Вряд ли! Так как количество записей — есть первое измерение вариантного массива (необходимо здесь тире или нет???). А я не нашел до сих пор способа изменить первую размерность вариантного массива при наличии второй. Может, кто подскажет начинающему (про начинающего — правда)!!! Возможно, было бы правильно создать массив массивов (понимаете о чем я?). Но, что-то не заладилось там, Наверху. Поэтому такое решение не проходит. Точнее проходит, но как-то не очень хорошо — попробуйте!
Тем не менее, этот вариант вполне «живуч» при осторожном его использовании и на небольших объемах данных. Скорость нормальная, проблем с «3/7″ нет. В общем, больной будет жить!
