16 сентября 2019

Запись в MS Excel. Кто быстрее?


    В марте этого года я протестировал скорость чтение информации из файла MS Excel библиотеками работающие с файлом MS Excel "напрямую" (Чтение из MS Excel. Кто быстрее?). Сегодня давайте взглянем, как эти библиотеки справляются с записью файла.
    Мой тест создает новый XLSX-файл с одним листом, на который записывает 10000 строк по 100 столбцов.
const
  ciRowCount = 10000;
  ciColCount = 100;
Каждая библиотека формирует файл 10 раз и результатом теста является среднее время. В качестве компилятора использована RadStudio v10.3.2. А результаты подтверждены на другом компьютере с компиляцией в RadStudio v10.3.1.

Тест №1. Начнем с лидера по скорости чтения – с Axolot XLSReadWrite
procedure WriteXlsRW;
var
  XLS: TXLSReadWriteII5;
  j, iRow, iCol, iRowCount, iColCount: Integer;
  t: TStopwatch;
begin
  iRowCount := ciRowCount - 1;
  iColCount := ciColCount - 1;
  Write('1. XLSReadWrite: ');
  t := t.StartNew;
  for j := 1 to 10 do
    begin
      xls := TXLSReadWriteII5.Create(nil);
      try
        for iRow := 0 to iRowCount do
          for iCol := 0 to iColCount do
            xls[0].AsInteger[iCol, iRow] := iCol+iRow;
        xls.SaveToFile('XLrw.xlsx');
      finally
        xls.Free;
      end;
    end;
  t.Stop;
  WriteLn(t.ElapsedMilliseconds div 10);
end;
Результаты
32-бит: 1323 мс
64-бит: 1595 мс

Тест №2. Оказалось, что по аналогии с "DirectRead mode" для чтения у Axolot XLSReadWrite есть "DirectWrite mode" для записи
type
  TOnWriteCell = class(TObject)
    procedure XLSWriteCell(ACell: TXLSEventCell);
  end;

procedure TOnWriteCell.XLSWriteCell(ACell: TXLSEventCell);
begin
  ACell.AsFloat := ACell.Col + ACell.Row;
end;

procedure WriteXlsRWd;
var
  xls: TXLSReadWriteII5;
  wc: TOnWriteCell;
  t: TStopwatch;
  j: Integer;
begin
  Write('2. XLSReadWrite Direct: ');
  t := t.StartNew;
  for j := 1 to 10 do
    begin
      wc  := nil;
      xls := TXLSReadWriteII5.Create(nil);
      try
        xls.SetDirectWriteArea(0, 0, 0, ciColCount - 1, ciRowCount - 1);
        xls.Filename := 'XLrwD.xlsx';
        xls.DirectWrite := True;
        wc := TOnWriteCell.Create;
        xls.OnWriteCell := wc.XLSWriteCell;
        xls.Write;
      finally
        xls.Free;
        wc.Free;
      end;
    end;
  t.Stop;
  WriteLn(t.ElapsedMilliseconds div 10);
end;
Результаты
32-бит: 1170 мс
64-бит: 1482 мс
Для 32-х бит прирост скорости в 153 мс. Это почти 12%!

Тест №3. Перейдем к TMS FlexCel
procedure WriteFlexCel;
var
  xls: TXlsFile;
  j, iRow, iCol: Integer;
  t: TStopwatch;
begin
  Write('3. FlexCel: ');
  t := t.StartNew;
  for j := 1 to 10 do
    begin
      xls := TXlsFile.Create(True);
      xls.NewFile(1);
      try
        for iRow := 1 to ciRowCount do
          for iCol := 1 to ciColCount do
            xls.SetCellValue(iRow, iCol, iCol+iRow);
        xls.Save('FlexCell.xlsx');
      finally
        xls.Free;
      end;
    end;
  t.Stop;
  WriteLn(t.ElapsedMilliseconds div 10);
end;
Результаты
32-бит: 1502 мс
64-бит: 1468 мс
32-х битная версия экспорта TMS FlexCel на 179 мс медленнее, чем XLSReadWrite. И на 332 мс медленнее XLSReadWrite в "DirectWrite mode"! Для меня это не совсем ожидаемый и приятный результат. Для тех, кто не читал заметку о тестировании импорта скажу: я много лет использовал XLSReadWrite, а лет 7-9 тому назад перешел на FlexCel.

Тест №4. Для полноты картины глянем на новичка в области экспорта данных в формат в MS Excel – на TXlsMemFileEh из EhLib
procedure WriteEh;
var
  xls: TXlsMemFileEh;
  Sheet: TXlsWorksheetEh;
  j, iRow, iCol, iRowCount, iColCount: Integer;
  t: TStopwatch;
begin
  iRowCount := ciRowCount - 1;
  iColCount := ciColCount - 1;

  Write('4. EhLib: ');
  t := t.StartNew;
  for j := 1 to 10 do
    begin
      xls   := TXlsMemFileEh.Create;
      Sheet := xls.Workbook.Worksheets[0];
      try
        for iRow := 0 to iRowCount do
          for iCol := 0 to iColCount do
            Sheet.Cells[iCol, iRow].Value :=  iCol+iRow;
        xls.SaveToFile('EhLib.xlsx');
      finally
        xls.Free;
      end;
    end;
  t.Stop;
  WriteLn(t.ElapsedMilliseconds div 10);
end;
Результаты
32-бит: 16063 мс
64-бит: 16271 мс
Проигрыш конкурентам по тесту больше чем в 10 раз! Так как EhLib – это не библиотека для работы с файлами MS Excel, то я понимал, что результат может быть печальным, но не думал, что настолько. Добавим к этому то, что файл от 32-х битной версии экспорта был сформирован не полностью и при его открытии MS Excel спросил: "Ошибка в части содержимого в книге EhLib.xlsx. Выполнить попытку восстановления?". Попытка восстановить закончилась неудачей: "Замененный компонент: часть /xl/worksheets/sheet1.xml с ошибкой XML. Непредусмотренный конец входных данных. Строка 2, столбец 10605714". При этом файл созданный 64-х битной версией экспорта открылся нормально. Это фиаско братан!

Итак, подведем итоги
Библиотека32-бит% от лучшего результата64-бит% от лучшего результатасредний %
Axolot XLSReadWrite1323113.081595108.65110.87
Axolot XLSReadWrite "DirectWrite mode"1170100.001482100.95100.48
TMS FlexCel1502128.381468100.00114.19
EhLib160631372.91162711108.381240.65

Выводы
1. Axolot XLSReadWrite является не только лидером по скорости чтении информации из файла MS Excel, но и по скорости записи в файл. Похоже на то, что для увеличения скорости работы утилит импорта/экспорта мне надо переходить обратно на XLSReadWrite...
2. TXlsMemFileEh из EhLib пока нельзя рассматривать как альтернативу библиотекам XLSReadWrite и FlexCel. Но я думаю, что он вполне подойдет для выгрузки нескольких десятков или сотен строк.

P.S. Использованы последние доступные на данный момент версии библиотек: Axolot XLSReadWrite v6.00.57, TMS FlexCel v7.0 и EhLib v9.4.015.

3 комментария:

  1. У меня есть опыт работы и с лицензионными XlsReadWrite и с FlexCel. Я остановилась на FlexCel, т.к. ощутила разницу в подходе к саппорту от авторов этих библиотек. Скорость отклика и готовность помочь - как небо и земля. Автор FlexCel всегда дает ответы и советы в течение нескольких часов или даже минут. А автор XLSReadWrite на форуме поддержки очень высокомерен.

    ОтветитьУдалить
  2. Скорость не главное. Главное - функциональные возможности. У flexcel они богаче и реализованы удобнее.

    ОтветитьУдалить
  3. Согласен, что скорость не главное. Но иногда скорость имеет значение. Например, у меня есть консольные утилиты, которыми пользователи конвертируют данные из одного формата или системы в другой формат или систему. Попутно с этими данными проводят различные манипуляции. Количество строк в этих файлах исчисляется сотнями тысяч строк (иногда и под миллион). В результате там несколько миллисекунд, там несколько секунд... На большом количестве файлов это заметное время.

    ОтветитьУдалить