ПредишенСледващото

За осемнадесет месеца ми предложиха няколко варианта за това как да се ускори четене на данни от работен лист на Excel - използването на MSXML библиотеки и други готови за себе си процедури и функции. Е, всеки проблем може да бъде решен по няколко начина. С няколко опции и да определи кой вариант би бил най-бързият. Е, какво опция би било по-удобно - това е всеки решава за себе си.


Четене на данни от Excel

Първо, помислете за възможността за четене на данни, използващи този грях онези, които са само началото им познаване на Excel в Делфи - четене на данни от всяка клетка поотделно. Процедура на изпитване с опцията за четене може да изглежда така:

процедура TForm16.SlowVariant;
VAR редове, колони, I, J: цяло число;
Работен лист: OLEVariant;
г: TDateTime;
започвам
// отворена книга
ExcelApp.Workbooks.Open (edFile.Text);
// получи активното лист
Лист: = ExcelApp.ActiveWorkbook.ActiveSheet;
// определяне на броя на редовете и колоните на таблицата
Редове: = WorkSheet.UsedRange.Rows.Count;
Графи: = WorkSheet.UsedRange.Columns.Count;

StringGrid1.RowCount: = редове;
StringGrid1.ColCount: = колони;

// определите началото на четене
г: = сега;

// показване на данните в табличен вид
за I: = 0 до редове-1 направят
за к: = 0 до колони-1 направи
StringGrid1.Cells [J, I]: = WorkSheet.UsedRange.Cells [I + 1, J + 1] .Value;

Label2.Caption: "цялото време лист четене" = + FormatDateTime ( "чч: мм: сс: ZZZ"
Сега () - г);
приключи;

Броячът в крайна сметка ще съдържа времето за четене и StringGrid изходните данни. Това би било възможно да се направи тезгяха само за четене на данни от листа, но реших да не се претовари изходните повтарящите се променливи. Ако има желание - може да бъде пренаписана малко изходния код и да получите "чисто" време за четене.

Excel лист се генерира за изпитването на това изпълнение с 143 реда и 142 колони с данни, т.е. 20306 клетки с данни. Фигурата по-долу показва брояч стойност при четене на данни:

12 секунди, за да се четат. и ако 1000 редове и колони 1000? Така че не може да чака за края на операцията.

Ако се вгледате внимателно в процедурата, представена по-горе, можем да видим, че всеки път, когато цикъл в началото на всяка итерация стигнем диапазона заета от данните, а след това този диапазон получава определена клетка и след това се отчита стойността в клетката. В действителност, толкова много ненужни операции за четене на данни от не се изисква листа. Особено, когато данните са разположени непрекъснато масив. По-изгодно в този случай един ще се чете да чете данни директно от целия обхват на масива.

В действителност, което прави този вид работа, би било още по-лесно, отколкото представени по-горе. Вижте сами. Тук е опция за четене на данни от редица:

процедура TForm16.RangeRead;
VAR редове, колони, I, J: цяло число;
Работен лист: OLEVariant;
FData: OLEVariant;
г: TDateTime;
започвам
// отворена книга
ExcelApp.Workbooks.Open (edFile.Text);
// получи активното лист
Лист: = ExcelApp.ActiveWorkbook.ActiveSheet;
// определяне на броя на редовете и колоните на таблицата
Редове: = WorkSheet.UsedRange.Rows.Count;
Графи: = WorkSheet.UsedRange.Columns.Count;

// Прочети целия диапазон на данни
FData: = WorkSheet.UsedRange.Value;

// определите началото на четене
г: = сега;

// показване на данните в табличен вид
за I: = 0 до редове-1 направят
за к: = 0 до колони-1 направи
StringGrid1.Cells [J, I]: = FData [I + 1, J + 1];

Label2.Caption: "цялото време лист четене" = + FormatDateTime ( "чч: мм: сс: ZZZ"
Сега () - г);
приключи;

Очакваме по време на операцията:

Както можете да видите, скоростта на растеж е огромен, дори и като се има предвид факта, че на уреда има актуализация време StringGrid'a.

Тук би било подходящо да се покаже обратния начин на работа с Excel, т.е. запис на данни върху лист Excel с помощта на вариант масив.
Писане на данни към Excel

Ако ние трябва да се напише голямо количество данни в лист Excel, ние трябва да се извърши обратната операция, т.е. първо да създадете вариант масив, след това да напишете данните в масива и след това да напишете целия масив в една операция в Excel. Например, аз написах една рутинна, която гласи голямо количество данни от StringGrid и изпраща данни на втория лист на Excel отворена книга:

процедура TForm16.WriteData;
Var, Й: цяло число;
FData: Вариант;
Лист, обхват: Вариант;
започвам
// създаде вариант масив
FData: = VarArrayCreate ([1, StringGrid1.RowCount, 1, StringGrid1.ColCount] varVariant);
// запълване на масива с данни от StringGrid
защото: = 1 до VarArrayHighBound (FData, 1) направи
за к: = 1 до VarArrayHighBound (FData, 2) направи
FData [Ь, й]: = StringGrid1.Cells [J-1, I-1];

// отворена книга
ExcelApp.Workbooks.Open (edFile.Text);
// активирате
Спецификация: = ExcelApp.ActiveWorkBook.Sheets [2];
Sheet.Activate;
// изберете диапазона, за да вмъкнете данни
Обхват: = Sheet.Range [Sheet.Cells [1,1], Sheet.Cells [VarArrayHighBound (FData, 1), VarArrayHighBound (FData, 2])];
// въведете данните
Range.Value: = FData;
// Показване на прозореца на Excel
ExcelApp.Visible: = True;
приключи;

Ето, ние първо да създадете двумерен вариант масив, използвайки метод VarArrayCreate, а след това попълнете масива от данни и да премине на масива за Excel. Имайте предвид, че не използва никакви линии в Excel, когато записвате - запис се извършва в 2 лесни стъпки:
изберете периода, като се използва набор от границите първата и последната клетка
задаване диапазон от стойности от масив.

За пълнота, на следващата фигура показва стойността на брояча, който се изчислява от момента на създаването на масива да Excel, за да активирате приложението включва:

Естествено, ръстът на данни ще продължи да расте и да извършва операцията. Например, лист, съдържащ 1000 реда и 256 колони напълнени с данни за 7 секунди. Ако имате такъв момент, е неприемливо, а след това по-горе процедура може да бъде леко се ускори с помощта на чифт VarArrayLock () и VarArrayUnlock (), но трябва да се има предвид, че FData матрица ще бъде транспонирана.

Какво друго е необходимо да се каже за четене / запис на данни в Excel. Вероятно, че методите, предложени по-горе дела, без да успеят да изискват Excel, инсталирана на компютъра, на който стартирате програмата. Във връзка с това, може да се наложи по-гъвкав начин на работа с Excel. Тук отново може да има няколко версии на работата, но аз ще се появи, а по-скоро посоча само един от тях - с XLSReadWrite библиотека.

Един опростен пример за Delphi 7
Var
IntlXls: TXLSReadWriteII2;
I, J: цяло число;

започвам
// създаде обект
IntlXls: = TXLSReadWriteII2.Create (нула);

// заглавие на книгата
IntlXls.Sheets [0] .name: = "Заглавието на доклада ми";
// добавете необходимия брой редове и колони
IntlXls.Sheets [0] .Rows.AddIfNone (0, 10000);
IntlXls.Sheets [0] .Columns.AddIfNone (0, 100);

// добавят и ширина буксуване клетка (пиксел стойност)
за I: = 0 до 99 направи
IntlXls.Sheets [0] .Columns [I] .PixelWidth: = 150;
// занасяне височина на редове (стойност не е в пиксели, така че трябва да се коригира)
за I: = 0-9999 направи
IntlXls.Sheets [0] .Rows [I] .Height: = 20 * 14;

// създаде
за J: = 0-9999 направи
за I: = 0 до 99 направи
започвам
// настоява цифрова стойност
// ако искате да въведете такава линия, а след това използвайте AsString
IntlXls.Sheets [0] .AsFloat [I, J]: = J + I / 100;

// хоризонтално подреждане (на разположение chaLeft, chaCenter, chaRight)
IntlXls.Sheets [0] .Cell [I, J] .HorizAlignment: = chaLeft;

// вертикално подравняване (достъпно cvaTop, cvaCenter, cvaBottom)
IntlXls.Sheets [0] .Cell [I, J] .VertAlignment: = cvaTop;

// шрифта
IntlXls.Sheets [0] .Cell [I, J] .FontName: = "Arial";
IntlXls.Sheets [0] .Cell [I, J] .FontSize: = 12;
IntlXls.Sheets [0] .Cell [I, J] .FontStyle: = [];
IntlXls.Sheets [0] .Cell [I, J] .FontColor: = TColorToClosestXColor (clBlue);
IntlXls.Sheets [0] .Cell [I, J] .Rotation: = 0;
// получер шрифт
с IntlXls.Sheets [0] .Cell [I, J] направи
FontStyle: = FontStyle + [xfsBold];
// наклонения марки
с IntlXls.Sheets [0] .Cell [I, J] направи
FontStyle: = FontStyle + [xfsItalic];
// фонов цвят
IntlXls.Sheets [0] .Cell [I, J] .FillPatternForeColor: =
TColorToClosestXColor (clYellow);

// бордюра в ляво (същото като останалата част от границите)
IntlXls.Sheets [0] .Cell [I, J] .BorderLeftColor: =
TColorToClosestXColor (clBlack);
IntlXls.Sheets [0] .Cell [I, J] .BorderLeftStyle: = cbsThin;

// слеят клетки (комбинират тук две хоризонтални клетки)
ако I = 49 тогава
IntlXls.Sheets [0] .MergedCells.Add (I, J, I + 1, J);
приключи;

IntlXls.SaveToFile ( "C: \ demo.xls");
IntlXls.Free;
приключи;

Пълен пример на библиотеката:

// хоризонтално подравняване
При HorizAlign на
haLeft:
// вляво,
IntlXls.Sheets [0] .Cell [IntlCol, IntlRow] .HorizAlignment
: = ChaLeft;
haCenter:
// центриран
IntlXls.Sheets [0] .Cell [IntlCol, IntlRow] .HorizAlignment: =
chaCenter;
haRight:
// дясно подравняване
IntlXls.Sheets [0] .Cell [IntlCol, IntlRow] .HorizAlignment
: = ChaRight;
приключи; // случай
// вертикално подравняване
При VertAlign на
vaTop:
// горната схема
IntlXls.Sheets [0] .Cell [IntlCol, IntlRow] .VertAlignment
: = CvaTop;
vaCenter:
// подравняване в центъра
IntlXls.Sheets [0] .Cell [IntlCol, IntlRow] .VertAlignment: =
cvaCenter;
vaBottom:
// долната схема
IntlXls.Sheets [0] .Cell [IntlCol, IntlRow] .VertAlignment: =
cvaBottom;
приключи; // случай
// шрифта
IntlXls.Sheets [0] .Cell [IntlCol, IntlRow] .FontName: = Font.Name;
IntlXls.Sheets [0] .Cell [IntlCol, IntlRow] .FontSize: = Font.Size;
IntlXls.Sheets [0] .Cell [IntlCol, IntlRow] .FontCharset: =
Font.Charset;
IntlXls.Sheets [0] .Cell [IntlCol, IntlRow] .FontStyle: = [];
IntlXls.Sheets [0] .Cell [IntlCol, IntlRow] .FontColor: =
TColorToClosestXColor (Font.Color);
IntlXls.Sheets [0] .Cell [IntlCol, IntlRow] .Rotation: = Font.Angle;
// трябва смело?
ако Font.IsBold след това
// там
с IntlXls.Sheets [0] .Cell [IntlCol, IntlRow] направи
FontStyle: = FontStyle + [xfsBold];
// има наклонена марка?
ако Font.IsItalic след това
// там
с IntlXls.Sheets [0] .Cell [IntlCol, IntlRow] направи
FontStyle: = FontStyle + [xfsItalic];
// фонов цвят
ако Color <> clWindow след това
// зададете цвят
IntlXls.Sheets [0] .Cell [IntlCol, IntlRow] .FillPatternForeColor: =
TColorToClosestXColor (Color);
край // ако
още
// просто активирате клетката (в противен случай по-долу можете да добавите граници)
IntlXls.Sheets [0] [.AsString IntlCol, IntlRow]: = ";

// бордюра в ляво там?
с Borders.Left правя
ако LineHeight> 0, тогава
// създаде
започвам
// цвят
IntlXls.Sheets [0] .Cell [IntlCol, IntlRow] .BorderLeftColor: =
TColorToClosestXColor (Color);
// дебелината
ако LineHeight = 1 тогава
// тънък
IntlXls.Sheets [0] [.Cell IntlCol, IntlRow] .BorderLeftStyle
: = CbsThin
иначе, ако LineHeight в [1, 2] тогава
// средна дебелина
IntlXls.Sheets [0] .Cell [IntlCol, IntlRow] .BorderLeftStyle: =
cbsMedium
още
// дебелина
IntlXls.Sheets [0] [.Cell IntlCol, IntlRow] .BorderLeftStyle
: = CbsHair;
приключи; // ако с
// ограничаване на върха там?
с Borders.Top правя
ако LineHeight> 0, тогава
// създаде
започвам
// цвят
IntlXls.Sheets [0] .Cell [IntlCol, IntlRow] .BorderTopColor: =
TColorToClosestXColor (Color);
// дебелината
ако LineHeight = 1 тогава
// тънък
IntlXls.Sheets [0] [.Cell IntlCol, IntlRow] .BorderTopStyle
: = CbsThin
иначе, ако LineHeight в [1, 2] тогава
// средна дебелина
IntlXls.Sheets [0] .Cell [IntlCol, IntlRow] .BorderTopStyle: =
cbsMedium
още
// дебелина
IntlXls.Sheets [0] [.Cell IntlCol, IntlRow] .BorderTopStyle
: = CbsHair;
приключи; // ако с
// ограничи точно там?
с Borders.Right правя
ако LineHeight> 0, тогава
// създаде
започвам
// цвят
IntlXls.Sheets [0] .Cell [IntlCol, IntlRow] .BorderRightColor: =
TColorToClosestXColor (Color);
// дебелината
ако LineHeight = 1 тогава
// тънък
IntlXls.Sheets [0] [.Cell IntlCol, IntlRow] .BorderRightStyle
: = CbsThin
иначе, ако LineHeight в [1, 2] тогава
// средна дебелина
IntlXls.Sheets [0] .Cell [IntlCol, IntlRow] .BorderRightStyle: =
cbsMedium
още
// дебелина
IntlXls.Sheets [0] [.Cell IntlCol, IntlRow] .BorderRightStyle
: = CbsHair;
приключи; // ако с
// Bottom граница е?
с Borders.Bottom задачи
ако LineHeight> 0, тогава
// създаде
започвам
// цвят
IntlXls.Sheets [0] .Cell [IntlCol, IntlRow] .BorderBottomColor: =
TColorToClosestXColor (Color);
// дебелината
ако LineHeight = 1 тогава
// тънък
IntlXls.Sheets [0] [.Cell IntlCol, IntlRow] .BorderBottomStyle
: = CbsThin
иначе, ако LineHeight в [1, 2] тогава
// средна дебелина
IntlXls.Sheets [0] .Cell [IntlCol, IntlRow] .BorderBottomStyle: =
cbsMedium
още
// дебелина
IntlXls.Sheets [0] [.Cell IntlCol, IntlRow] .BorderBottomStyle
: = CbsHair;
приключи; // ако с
// асоциация трябва?
ако ((Range.Width> 1) или (Range.Height> 1)) и
((IntlMainCol = IntlCol) и (IntlMainRow = IntlRow)), тогава
// комбинирате
IntlXls.Sheets [0] .MergedCells.Add (IntlCol, IntlRow,
IntlCol + Range.Width - 1, IntlRow + Range.Height - 1);
// потребител натисне за прекъсване на износа?
ако btnCancel.Tag = 2 след това
// да, ние ще оставим
Счупете;
приключи; // с
приключи; // за
// актуализация на състоянието
prgrbrStatus.Position: = prgrbrStatus.Position + 1;
Application.ProcessMessages;
// потребител натисне за прекъсване на износа?
ако btnCancel.Tag = 2 след това
// да, ние ще оставим
Счупете;
приключи; // за
// потребител натисне за прекъсване на износа?
ако btnCancel.Tag <> 2 след
// не
започвам
// левия горен ъгъл
IntlXls.Sheet [0] .TopRow: = 0;
IntlXls.Sheet [0] .LeftCol: = 0;
IntlXls.Sheet [0] .Selection.ActiveRow: = 0;
IntlXls.Sheet [0] .Selection.ActiveCol: = 0;

// статус
prgrbrStatus.Position: = prgrbrStatus.Max;
Application.ProcessMessages;
// запис във файл
IntlXls.FileName: = AFileName;
IntlXls.Write;
// всички успешно
Резултат: = UNIRPT_OK;

край // ако
още
// да
Резултат: = UNIRPT_GENERATE_ABORT;

накрая
// освобождаване на паметта
IntlXls.Free;
приключи; // try..finally
приключи; // функция ExportToExcelXls

Свързани статии

Подкрепете проекта - споделете линка, благодаря!