Delphi выгрузка в excel
Пример из проекта, собирал по всему интернету для себя. Возможно кому-то ещё понадобится.
uDBConnection , System . Win . ComObj , System . AnsiStrings , System . IOUtils , Vcl . Forms ,
sql . Text : = 'SELECT value FROM salesforecast_db.servicetable where name=' 'salesXLSFileCount' ';' ;
sql . Text : = DBConnection_Sales . qCountSales . SQL . Text ;
filePath : = ExtractFilePath ( Application . ExeName ) + 'sales.xlsx' ;
// e.ActiveWorkBook.WorkSheets[1].Cells[1, 2] := 'Текст ячейки (1,2)';
e . ActiveSheet . PageSetup . LeftMargin : = e . Application . InchesToPoints ( 0.44 ) ;
e . ActiveSheet . PageSetup . RightMargin : = e . Application . InchesToPoints ( 0.44 ) ;
e . ActiveSheet . PageSetup . TopMargin : = e . Application . InchesToPoints ( 0.44 ) ;
e . ActiveSheet . PageSetup . BottomMargin : = e . Application . InchesToPoints ( 0.44 ) ;
e . ActiveWorkBook . WorkSheets [ 1 ] . cells [ 1 , 1 ] : = 'Дата' ;
e . ActiveWorkBook . WorkSheets [ 1 ] . cells [ 1 , 2 ] : = 'Номер' ;
e . ActiveWorkBook . WorkSheets [ 1 ] . cells [ 1 , 3 ] : = 'Отдел' ;
e . ActiveWorkBook . WorkSheets [ 1 ] . cells [ 1 , 4 ] : = 'Название' ;
e . ActiveWorkBook . WorkSheets [ 1 ] . cells [ 1 , 5 ] : = 'Цена' ;
e . ActiveWorkBook . WorkSheets [ 1 ] . cells [ 1 , 6 ] : = 'Количество' ;
e . ActiveWorkBook . WorkSheets [ 1 ] . cells [ 1 , 7 ] : = 'Сумма' ;
e . ActiveWorkBook . WorkSheets [ 1 ] . cells [ 1 , 8 ] : = 'Устройство' ;
sql . Text : = DBConnection_Sales . qSales . SQL . Text + 'limit ' + countRecAlreadyExported . ToString + ',10000' ;
e . ActiveWorkBook . WorkSheets [ 1 ] . cells [ i , 1 ] : = DateTimeToStr ( FieldByName ( 'localDate' ) . AsDateTime ) ;
e . ActiveWorkBook . WorkSheets [ 1 ] . cells [ i , 2 ] : = FieldByName ( 'doubleNumber' ) . AsString ; //doubleNumber
e . ActiveWorkBook . WorkSheets [ 1 ] . cells [ i , 3 ] : = FieldByName ( 'depName' ) . AsString ; // 'Отдел'; //depName
e . ActiveWorkBook . WorkSheets [ 1 ] . cells [ i , 4 ] : = FieldByName ( 'goodName' ) . AsString ; //'Название';
e . ActiveWorkBook . WorkSheets [ 1 ] . cells [ i , 5 ] : = FormatFloat ( '0.00' , FieldByName ( 'price' ) . AsFloat ) ; //'Цена';
e . ActiveWorkBook . WorkSheets [ 1 ] . cells [ i , 6 ] : = FieldByName ( 'quantity' ) . AsInteger . ToString ( ) ; //'Количество'; //quantity
e . ActiveWorkBook . WorkSheets [ 1 ] . cells [ i , 7 ] : = FormatFloat ( '0.00' , FieldByName ( 'summ' ) . AsFloat ) ;
e . ActiveWorkBook . WorkSheets [ 1 ] . cells [ i , 8 ] : = FieldByName ( 'deviceName' ) . AsString ; //'Устройство'; //
При написании бизнес приложений на Delphi, выполняющих какие либо расчеты, может возникнуть необходимость импорта (экспорта) данных из файлов других приложений. Одно из основных таких приложений – MS Excel. Как прочитать файлы xls в Delphi мы сейчас и рассмотрим!?
Создадим новый проект и разместим на форме три компонента:
StringGrid – находится на палитре компонентов, во вкладке Additional
Кнопку Button и для удобства выбора файлов, диалог открытия файлов (работа с диалогами описана здесь).
Для StringGrid, в свойствах(Properties) укажем следующее:
DefaultRowHeight – 17
FixedCols – 0
FixedRows – 0
В результате форма будет выглядеть примерно так:
На этом украшательства закончим и приступим к написанию кода.
Для работы с Excel файлами нам понадобится библиотека ComObj, входящая в стандартную поставку Delphi. Подключается она в разделе Uses. Добавьте в конце, после запятой «ComObj».
Теперь опишите процедуру Xls_Open после ключевого слова implementation:
procedure Xls_Open(XLSFile:string; Grid:TStringGrid);
const
xlCellTypeLastCell = $0000000B;
var
ExlApp, Sheet: OLEVariant;
i, j, r, c:integer;
begin
//создаем объект Excel
ExlApp := CreateOleObject('Excel.Application');
//делаем окно Excel невидимым
ExlApp.Visible := false;
//открываем файл XLSFile
ExlApp.Workbooks.Open(XLSFile);
//создаем объект Sheet(страница) и указываем номер листа (1)
//в книге, с которого будем осуществлять чтение
Sheet := ExlApp.Workbooks[ExtractFileName(XLSFile)].WorkSheets[1];
//активируем последнюю ячейку на листе
Sheet.Cells.SpecialCells(xlCellTypeLastCell, EmptyParam).Activate;
// Возвращает номер последней строки
r := ExlApp.ActiveCell.Row;
// Возвращает номер последнего столбца
c := ExlApp.ActiveCell.Column;
//устанавливаем кол-во столбцов и строк в StringGrid
Grid.RowCount:=r;
Grid.ColCount:=c;
//считываем значение из каждой ячейки и копируем в нашу таблицу
for j:= 1 to r do
for i:= 1 to c do
Grid.Cells[i-1,j-1]:= sheet.cells[j,i];
//если необходимо прочитать формулы то
//Grid.Cells[i-1,j-1]:= sheet.cells[j,i].formula;
//закрываем приложение Excel
ExlApp.Quit;
//очищаем выделенную память
ExlApp := Unassigned;
Sheet := Unassigned;
end;
Наша процедура Xls_Open имеет два входных параметра:
- XLSFile – путь к файлу Excel (xls)
- Grid – таблица, в которую будем осуществлять вывод данных.
В комментариях к коду я постарался все расписать, объясню немного принцип работы процедуры.
Мы создаем в памяти объект ExlApp с приложением Excel.Application. Затем указываем что этот объект будет невидим для пользователя ExlApp.Visible := false (если false заменить на true, то при открытии файла мы увидим окно Excel с открываемым файлом). Далее открывается файл ExlApp.Workbooks.Open(XLSFile). Потом создаем еще один объект Sheet, который позволяет работать с листом книги Excel: Sheet := ExlApp.Workbooks[ExtractFileName(XLSFile)].WorkSheets[1]. Единица в конце указывает номер листа с которого будем читать данные (к листам можно обращаться по имени, для этого вместо 1 указываем «ИмяЛиста1»). Далее определяем кол-во строк и столбцов которые содержат данные, и используя циклы For считываем данные копируя их в StringGrid. Впринципе и все.
Для использования процедуры Xls_Open пропишем в событие Click кнопки Button1 следующее:
If OpenDialog1.Execute then Xls_Open (OpenDialog1.FileName, StringGrid1);
Основные недостатки этого способа: медленное чтение данных (хотя для небольших файлов вполне сгодится) и необходимость установленной версии Excel на компьютере пользователя.
Полный листинг программы:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Grids, StdCtrls,ComObj;
type
TForm1 = class(TForm)
StringGrid1: TStringGrid;
Button1: TButton;
OpenDialog1: TOpenDialog;
procedure Button1Click(Sender: TObject);
private
public
end;
var
Form1: TForm1;
implementation
procedure Xls_Open(XLSFile:string; Grid:TStringGrid);
const
xlCellTypeLastCell = $0000000B;
var
ExlApp, Sheet: OLEVariant;
i, j, r, c:integer;
begin
//создаем объект Excel
ExlApp := CreateOleObject('Excel.Application');
//делаем окно Excel невидимым
ExlApp.Visible := false;
//открываем файл XLSFile
ExlApp.Workbooks.Open(XLSFile);
//создаем объект Sheet(страница) и указываем номер листа (1)
//в книге, с которого будем осуществлять чтение
Sheet := ExlApp.Workbooks[ExtractFileName(XLSFile)].WorkSheets[1];
//активируем последнюю ячейку на листе
Sheet.Cells.SpecialCells(xlCellTypeLastCell, EmptyParam).Activate;
// Возвращает номер последней строки
r := ExlApp.ActiveCell.Row;
// Возвращает номер последнего столбца
c := ExlApp.ActiveCell.Column;
//устанавливаем кол-во столбцов и строк в StringGrid
Grid.RowCount:=r;
Grid.ColCount:=c;
//считываем значение из каждой ячейки и копируем в нашу таблицу
for j:= 1 to r do
for i:= 1 to c do
Grid.Cells[i-1,j-1]:= sheet.cells[j,i];
//если необходимо прочитать формулы то
//Grid.Cells[i-1,j-1]:= sheet.cells[j,i].formula;
//закрываем приложение Excel
ExlApp.Quit;
//очищаем выделенную память
ExlApp := Unassigned;
Sheet := Unassigned;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
If OpenDialog1.Execute then Xls_Open (OpenDialog1.FileName, StringGrid1);
end;
end.
Обновленный пример. Добавлена функция отбора строк по критерию. Так же добавлен обработчик делающий отображение шрифта "шапки" в StringGrid жирным. Все дополнения постарался по максимуму раскомментить
Когда задача стоит “Сохранить из Delphi или Lazarus в Excel” у разработчика просто огромный выбор - частично он описан в статье “Как записать в XLS Biff8 из Delphi”, там же я вкратце расписал, почему это плохой выбор. А что же тогда хорошо? А хорошо - сохранять в новый (ну, относительно новый) XML XLSX.
"XML является технологией, разработанной для управления структурированными данными и отображения этих данных в виде удобочитаемого текстового файла. Язык XML соответствует отраслевым стандартам и может быть обработан многими базами данных и приложениями. С помощью XML многие разработчики могут создавать собственные настроенные теги, структуры данных и схемы. В целом XML существенно облегчает определение, передачу, проверку и интерпретацию данных в различных базах данных, приложениях и организациях. "
Но Microsoft не был бы собой, если бы, традиционно не попытался сделать “свой собственный XML - c блэкджеком и ячейками!”. А потому у Excel на самом деле есть не один а целых два(!) XML-стандарта для хранения Excel-файлов: более ранний и более правильный.
Как я уже неоднократно указывал, FastReport позволяет сохранять из Delphi и Lazarus ваши документы, отчёты информацию в великое множество форматов. Сделать сам отчёт - легче лёгкого, можно посмотреть в прошлых статьях - единственное, опять остановлюсь-отмечу - следите за выравниванием ваших объектов, чтобы результирующие табличные форматы получались красивыми качественными! Так вот - для Excel XML у нас два разных(!) фильтра экспорта. Вот, полюбуйтесь!
Видим окно предварительного просмотра и кнопку “сохранить”
“Эй, уважаемый, а мне, простому программисту чем пользоваться?!” - спросите вы и будете совершенно правы. Короткий ответ - 2007 XML, более поздний. А ниже я расскажу, почему.
Понятно, что программист никогда не делает “потому, что захотелось” - хочется чего-либо пользователю. В чём же разница в этих двух форматах с точки зрения пользователя, жаждущего получить таблицу Excel из приложения? Со стороны пользователя разница примерно как между rft без картинок и полноценным файлом MS Word, и первый в реальной жизни почти не встречается. В простом XML нет, ни стилей ни картинок. Просто таблица в XML. Но в момент, когда его придумывали, и выбора-то особо не было - это был огромный шаг вперёд для MS Excel. А вот Microsoft Excel 2007 XML может хранить картинки , там есть стили и тд. Это контейнер OOML.
Углубиться в тему XML используемого с 2007 и далее можно тут - там целый мир!
А мы просто сравним два варианта сохранения в XML и XLSX XML и решим, какой использовать рациональнее и в каких случаях.
Экспорт в XML - более простой. Экспортируются только текстовые объекты. Изображения, графики, карты, штрихкоды, форматирование TfrxRichView, HTML-тэги и фоновое изображение в результирующий Excel XML не попадут.
Настройки экспорта – большее визуальное соответствие с начальным вариантом (WYSIWYG), разрыв страницы, и continuous - непрерывный документ с пропуском промежуточных заголовков и подвалов страниц.
Как будет выглядеть результат: без разделения, разделение на листы с использованием страниц отчёта, Use print on parent - каждой странице TfrxReportPage в шаблоне отчёта соответствует лист книги (при условии, что TfrxReportPage.PrintOnParent = False) или же поделить на части с задаваемым количеством строк.
Открыть после экспорта – результирующий файл будет открыт сразу же после экспорта программой Microsoft Excel (Ну или что у пользователя в системе ассоциировано с файлами расширения XLSX для их открытия).
Сравним получившиеся XLSX и Excel XML
Первый скриншот - это результат сохранения в формате XLSX и как мы видим, данный формат не поддерживает данные сложнее обычного текста. А вот второй скриншот показывает нам все возможности формата XML, т.е. полную поддержку штрихкодов, картинок. Если говорить про вес файлов, то результат ожидаемый: XLSX 48,0 КБ, XML 40,0 КБ.
Разберёмся подробнее почему XLSX весит больше XML. За основу взяли вот этих прекрасных рыбок. Данный документ содержит много текста, табличные данные и 30 фотографий. Для большей наглядности сравним ещё и нестареющий Excel 97, о котором мы говорили в другой статье.
Excel 97 - Формат двоичных файлов, бинарник (biff8), про сжатие тут не слышали и потому вес файла столь велик. В отличии от более позднего XML, формат 97 года поддерживает все виды изображений.
Excel table (XML) - Ранняя версия XLSX, где данные хранятся как простые одиночные монолитные XML-файлы, что делает их довольно большими, по сравнению с OOXML и устаревшими двоичными форматами Microsoft Office. Но на скриншоте вес минимален - возмутился бы каждый! Ответ прост, данный вес указан за документ, где отображаться будет только текст. А теперь представьте, если бы тут всё-таки была поддержка картинок, да он бы занимал кучу места, ведь о сжатии на этом моменте всё ещё никто не знает. Кроме того, встроенные элементы, такие как изображения, хранятся в виде двоичных закодированных блоков, но недоступны для отображения.
Excel 2007 XLSX (XML) - Microsoft взяли лучшее от прошлых форматов и внедрили сжатие файлов. Размер документа приблизительно на 50-75 процентов меньше, чем в предыдущих версиях.
Ограниченные возможности и возможные ограничения формата XLSX Excel 2007
Количество столбцов увеличилось с 256 до 16 384, количество строк в листе возросло с 65 536 до 1 048 576. Ускорены вычисления в больших листах, содержащих множество формул, благодаря поддержке Office Excel 2007 нескольких процессоров и многопоточных наборов микросхем.
О, это вечная тема - сделать таблицу Эксель из Delphi.
Таблицы Excel – сегодня один из мировых стандартов. А для программ, даже простых, частое требование – это вывод данных в виде таблиц и перенос отчёта в таблицу. Сразу отмечу, что XLS формат уже устаревший, это внутренний формат Microsoft Excel под названием Biff8 (целый мир со своими взаимосвязями между, с первого взгляда, никак не связанными сущностями, ячейками, бесконечными вкладками и страницами с участками файла, записанного в хардкорном бинарном формате), тем не менее - есть компании, заказчики, у которых именно такое требование. Таких заказчиков хорошо бы сразу палкой по голове бить предупредить, что для реальных больших данных этот формат НЕ ГОДИТСЯ - сами полюбуйтесь :
"Excel has limits on the amount of data a cell can hold: for Excel BIFF 8 files, that limit is 32,767 characters, so (in theory) 200+ characters should not be an issue. However, for longer strings, this data is maintained in the BIFF file across several blocks with continuation records, For BIFF 5 files (Excel 95) the limit is 2084 bytes per block; in BIFF 8 files (Excel 97 and above) the limit is 8228 bytes. Records that are longer than these limits must be split up into CONTINUE blocks."
- там и число столбцов, и строк, и данных в них - ограничены. Лучше уж что-то новое использовать. В другой статье я расскажу, как сохранять из Delphi в XLSX XML (куда как более приятные форматы - хотя тоже Excel).
Но если уж захотелось странного, и недостатки формата вас не испугали, то пойдём пугаться дальше тут есть несколько возможностей:
- Вывод таблицы XLS прямо сразу из StringGrid через вызовы OLE / OLE-container - у этого способа есть несколько неприятных моментов - вам всенепременно нужен установленный Microsoft Excel на компьютере (мы же не пираты какие - обязательно купить лицензию надо!), разрядность системы, установленного пакета MS Office и вашей скомпилированной программы должны совпадать (вы даже не представляете, сколько незабываемых часов отладки может сам доставить, например, 32-битный офис на 64-битной системе!), ваша табличка должна быть небольшой (на больших данных OLE, работая непосредственно в оперативной памяти, сразу упадёт с громким треском, потянув за собою и Excel и вашу программку), и даже для этой маленькой программки у вас должно быть достаточно времени. Процесс передачи серийных данных через OLE медитативен и не терпит суеты. Запрос “delphi ole excel container save file” скрасит вам не один вечер.
- Окей, предположим, хочется делать всё по-взрослому - и отправлять в XLS большие объемы данных. Тогда приходят на помощь всевозможные библиотеки для записи сразу в XLS - например, TXLSFile. Есть и у этого подхода некоторые недостатки. Например - изображения, картинки, штрихкоды в ячейки поместить, да те же рамки-обрамления ячеек - не то чтобы невозможно, но будут результатом некоторых, скажем так, усилий.
- Или TMS FlexCel. Вы можете сделать отчёт в TMS FlexCel с картинкаи и совсем без программирования. Если же вы хотите сделать это из кода, у них есть инструмент для его генерации! *
- Так а что же делать? Выход, как обычно в этом блоге, есть - и это FastReport VCL! Во-первых, спокойно, используя максимум визуальных прелестей, делаете документ, отчёт (называйте, как хотите - хоть каталог для своих дилеров - и это не шутка, люди и не такое делают), потом экспортируйте готовый результат, как он есть - в Excel! Да, используйте рекомендации по подготовке отчёта - делайте его сразу ТАБЛИЧНЫМ, “аккуратненько, под линеечку” - FastReport, понятно, постарается наложенные друг на друга объекты вписать в таблицу - но так из пары объектов может получиться до 9(!) ячеек - вам же самим не понравится такой результат!
Записываем XLS из Delphi c помощью FastReport
Итак, ваш документ содержит большие таблицы, многоуровневые списки, иллюстрации, карты, штрих-коды и вы думаете, как бы это перенести в Excel?
Не буду тут повторно останавливаться на создании отчёта - бросили на форму проекта TfrxReport, TfrxBIFFExport и TButton, прописали на кнопку вызов
- строим отчёт и запускаем окно предпросмотра того, что получилось.
Видим окно предварительного просмотра и кнопку “сохранить”
И, в принципе, как будет выглядеть результат: разбивать на страницы, оставив в изначальном виде, расположить всё на одной странице или же поделить на части с задаваемым количеством строк.
Открыть после экспорта – результирующий файл будет открыт сразу же после экспорта программой Microsoft Excel.
Служебная информация, которая также пойдёт в Excel-файл: название, автор, ключевые слова, версия документа, приложения, категория, менеджер и комментарий к файлу.
Безопасность — защита паролем документа (дополнительно можно указать подтверждение).
Если задать непустую строку пароля, то сгенерированный файл будет защищён паролем. Пароль пишется только символами Юникода и должен быть короче 256 символов.
Опции – настройка документа на большее визуальное соответствие с первоначальном вариантом (WYSIWYG), экспорт в таблицу картинок-изображений, отображения границ ячеек, выставлять размер страницы, удаление пустых строк (для экономии места в этом конкретном формате очень важная опция), экспорт формул.
Если не нужно столь подробно выставлять параметры, то можно оставить всё по умолчанию.
Отправка из Delphi / Lazarus в Excel(Biff8) из кода
Какие побочные эффекты у такого варианта создания Excel-листов из Delphi? Прежде всего, это на порядок быстрее и надёжнее, чем запись в XLS Biff8 через OLE-container (можете сами сравнить), да и возможности пошире (если, конечно, не нужно просто тупо выгнать StringGrid 100х100 в Excel, который гарантированно стоит на машинке без возможности обновлений), оно платформонезависимое (Linux-приложения, сделанные в Lazarus спокойно будут генерить XLS - и потом открыть в каком-нибудь Open Office / Libre Office), форматирование, свойства текста, цвета, картинки, штрих-коды, карты, графические примитивы из отчёта в результирующую Excel-таблицу будут сохранены (но учтите, Libre Office отказался показывать картинки, только MS Excel).
Вот так выгядит документ с иллюстрациями (рыбки) в Biff8 XLS. Каждая картинка в собственной ячейке.
Отчёт с картами после сохранения в формат Excel XLS (biff8). Некоторые ячейки были объединены.
Но и ограничения есть - вызваны самим выбранным форматом! На количество выгоняемых на одном листе Excel строк и столбцов - вот вам прямо кусок из кода:
Иначе бы оно при открытии сам MS Excel вываливался с ошибкой и не открывал бы таблицу. Формат, напомню, не развивается и уже давно морально устарел. Радует, что Microsoft не стоял на месте и (несколько позже, конечно, чем Fast Reports) понял таки преимущества XML в качестве базы для организации формата хранения. И о том, как сохранить из Delphi/Lazarus в Excel XML расскажем в следующей статье.
Читайте также: