15 сентября 2011

Конвертирование XLS/XLSX/XLSM в XLSB

   С появлением MS Excel 2007 на смену привычного XLS-файла пришли сразу три формата:
  • XLSX - стандартный формат файлов Excel 2007-2010 на основе XML;
  • XLSM - формат Excel 2007-2010 на основе XML с поддержкой макросов (в отличие от XLSX он позволяет сохранять код макросов MS Visual Basic для приложений (VBA) и листы макросов MS Excel 4.0 (XLM));
  • XLSB - формат двоичных файлов Excel 2007-2010 (BIFF12).
Наиболее интересным из них является формат XLSB - Excel Binary Workbook. В отличие от других форматов Excel 2007-2010, он хранит данные не в виде XML, а является двоичным. Это дает существенные преимущества при работе с большими таблицами, т.к. бинарные файлы занимают меньше места на диске и читаются/записываются быстрее.
   Ни одна из библиотек для работы с файлами Excel в Delphi не поддерживает XLSB-формат. Например, XLSReadWrite поддерживает только XLSX, а авторы TMS FlexCel вообще не могут сказать, когда у них будет поддержка формата Excel 2007 и будет ли вообще. Поэтому, что бы конвертировать файлы Excel в XLSB-формат необходимо использовать OLE:

Var
  xls: OleVariant;
...
Const
  // formats in Excel 2007-2010
  xlExcel12 = 50; // XLSB
  xlOpenXMLWorkbook = 51; // XLSX
  xlOpenXMLWorkbookMacroEnabled = 52; // XLSM
  xlExcel8 = 56; // XLS (export to Excel 97-2003)
...

Procedure XYZ.ConvertFilesToXLSB(slFiles: TStringList);
Var
  iFile: Integer;
begin
  Try
    Try
      xls := CreateOleObject('Excel.Application');
      xls.DisplayAlerts := False;
      If StrToFloat(StringReplace(xls.Version, '.', DecimalSeparator, [])) < 12
        then WriteToLog('Error! Requires Excel 2007/2010')
        else for iFile := 0 to slFiles.Count-1 do
                ConvertToXLSB(slFiles[iFile]);
    Finally
      xls.Quit;
      xls := UnAssigned;
    End;
  Except
    on E: Exception do
      WriteToLog(E.Message);
  End;
end;

Где ConvertToXLSB:

Procedure XYZ.ConvertToXLSB(sFileName: String);
Var
  sFileNameTo: String;
begin
  sFileName := ExpandFileName(sFileName);
  sFileNameTo := ChangeFileExt(sFileName, '.xlsb');
  Try
    Try
      xls.Workbooks.Open(sFileName);
      xls.ActiveWorkbook.SaveAs(Filename := sFileNameTo, FileFormat := xlExcel12);
    Finally
      xls.Workbooks.Close;
    End;
  Except
    on E: Exception do
      WriteToLog(E.Message);
  End;
end;

   Думаю, что код простой и комментировать нечего. Остановлюсь только на строке проверки версии MS Excel. xls.Version возвращает номер версии MS Excel в виде строки, где цифры разделены точкой (например, "11.0" для Excel 2003, "12.0" для Excel 2007...), поэтому, чтобы получить номер версии в виде числа его необходимо преобразовать следующим способом:

StrToFloat(StringReplace(xls.Version, '.', DecimalSeparator, []))