Делфи чрез АДО в ЕКСЕЛ
6 отговора
0 прегледа
Делфи чрез АДО в ЕКСЕЛ
Направих си екселски файл - с места за попълване. Тези места се вземат от друг файл със собствен формат (непознат за ексела) през делфи. Сложих АДО-то и направих връзките. Командата която озползвах за да забия едното число е:
form1.DataSource1.DataSet.Fields[0].Value:=I;
където I е Longint.
Да ама в Ексела ми го сложи в текстов формат и се налага да направя макросче, което да го обърне в числов. Макросчето не е проблем. Проблемът е че числата са мнооого в мнооого листи и само обръщане става бавно, а то требе са направи при зареждането в листа, понеще е възможно по-нататъшно допълване...
Пробвах с предварително форматиране на клетката в Ексела на число с 0 знака - се тая.
Пробвах и с:
form1.DataSource1.DataSet.Fields[0].AsInteger:=I;
е, не ще! Се в стринг ми го обръща...
Въпросът ми е:
Има ли някаква възможност да го обърна на число предварително, или да търся оптимизация после в Ексела, та да намаля времето за логин в таблицата?
Благодаря предварително.
form1.DataSource1.DataSet.Fields[0].Value:=I;
където I е Longint.
Да ама в Ексела ми го сложи в текстов формат и се налага да направя макросче, което да го обърне в числов. Макросчето не е проблем. Проблемът е че числата са мнооого в мнооого листи и само обръщане става бавно, а то требе са направи при зареждането в листа, понеще е възможно по-нататъшно допълване...
Пробвах с предварително форматиране на клетката в Ексела на число с 0 знака - се тая.
Пробвах и с:
form1.DataSource1.DataSet.Fields[0].AsInteger:=I;
е, не ще! Се в стринг ми го обръща...
Въпросът ми е:
Има ли някаква възможност да го обърна на число предварително, или да търся оптимизация после в Ексела, та да намаля времето за логин в таблицата?
Благодаря предварително.
Re: Делфи чрез АДО в ЕКСЕЛ
<?php
function xlsBOF($file) {
fwrite ($file, pack("ssssss", 0x809, 0x8, 0x0, 0x10, 0x0, 0x0));
return;
}
function xlsEOF($file) {
fwrite ($file, pack("ss", 0x0A, 0x00));
return;
}
function xlsWriteNumber($file, $Row, $Col, $Value) {
fwrite ($file, pack("sssss", 0x203, 14, $Row, $Col, 0x0));
fwrite ($file, pack("d", $Value));
return;
}
function xlsWriteLabel($file, $Row, $Col, $Value ) {
$L = strlen($Value);
fwrite ($file, pack("ssssss", 0x204, 8 + $L, $Row, $Col, 0x0, $L));
fwrite ($file, $Value);
return;
}
function MSSQL2XLS($rs,$strPath)
{
if (file_exists($strPath))
{unlink($strPath);}
$file=fopen($strPath,'w');
xlsBOF($file);
$rowsret = mssql_num_rows($rs);
$colsret = mssql_num_fields($rs);
for ($_col=1;$_col <= $colsret;$_col++)
{
xlsWriteLabel($file,0,$_col-1,trim(mssql_field_name($rs,$_col-1)));
}
mssql_data_seek($rs,0);
for($_row=1;$_row <= $rowsret;$_row++)
{ $row = mssql_fetch_row($rs);
for ($_col=1;$_col <= $colsret;$_col++)
{
if (mssql_field_type($rs,$_col-1)=='char')
{xlsWriteLabel($file,$_row,$_col-1,$row[$_col-1]);}
else
{xlsWriteNumber($file,$_row,$_col-1,$row[$_col-1]);}
}
}
xlsEOF($file);
mssql_data_seek($rs,0);
}
?>
function xlsBOF($file) {
fwrite ($file, pack("ssssss", 0x809, 0x8, 0x0, 0x10, 0x0, 0x0));
return;
}
function xlsEOF($file) {
fwrite ($file, pack("ss", 0x0A, 0x00));
return;
}
function xlsWriteNumber($file, $Row, $Col, $Value) {
fwrite ($file, pack("sssss", 0x203, 14, $Row, $Col, 0x0));
fwrite ($file, pack("d", $Value));
return;
}
function xlsWriteLabel($file, $Row, $Col, $Value ) {
$L = strlen($Value);
fwrite ($file, pack("ssssss", 0x204, 8 + $L, $Row, $Col, 0x0, $L));
fwrite ($file, $Value);
return;
}
function MSSQL2XLS($rs,$strPath)
{
if (file_exists($strPath))
{unlink($strPath);}
$file=fopen($strPath,'w');
xlsBOF($file);
$rowsret = mssql_num_rows($rs);
$colsret = mssql_num_fields($rs);
for ($_col=1;$_col <= $colsret;$_col++)
{
xlsWriteLabel($file,0,$_col-1,trim(mssql_field_name($rs,$_col-1)));
}
mssql_data_seek($rs,0);
for($_row=1;$_row <= $rowsret;$_row++)
{ $row = mssql_fetch_row($rs);
for ($_col=1;$_col <= $colsret;$_col++)
{
if (mssql_field_type($rs,$_col-1)=='char')
{xlsWriteLabel($file,$_row,$_col-1,$row[$_col-1]);}
else
{xlsWriteNumber($file,$_row,$_col-1,$row[$_col-1]);}
}
}
xlsEOF($file);
mssql_data_seek($rs,0);
}
?>
Re: Делфи чрез АДО в ЕКСЕЛ
Безкрайно съм благодарен за изчерпателния отговор. За да съм по-полезен с информацията, ще кажа следното:
1.Ползвам версия 7 на делфито
2.Офис пакета ми е 2003
3.Първото което направих е следния вариант:
ExcelName:='c:\aaa.xls';
Excel:=CreateOleObject('Excel.Application');
Excel.Visible:=False;
Excel.Workbooks.Open(ExcelName);
.... достъпа е по ред колона. Много удобно за писане, но доста по бавно.
Прекрасно за малки таблици
Excel.WorkBooks.close;
Excel.quit;
4.След това минах на варианта
ExcelName:='c:\aaa.xls';
AdoTable1.Active:=false;
ConnStr :='Provider=Microsoft.Jet.OLEDB.4.0;Data Source='+ExcelName +
';Extended Properties="Excel 8.0;HDR=No";Persist Security Info=False';
AdoTable1.ConnectionString:=ConnStr;
DataSource1.DataSet:=AdoTable1;
form1.ADOTable1.TableName:='Sheet1$';
form1.ADOTable1.Active:=true;
form1.DataSource1.DataSet.First;
form1.DataSource1.DataSet.edit;
form1.DataSource1.DataSet.Fields[0].Value:=1;
form1.DataSource1.DataSet.post;
form1.ADOTable1.Active:=false;
Четенето е ред по ред. Повече писане. Но програмчето се ускори с към 90%
(все пак говорим за над 2-3 милиона клетки които се ползват)
Та отвратителното на всичкото това е, че тази тъпа еденица дето я ръгам в А1,
след като отворя ексела си седи като текст -> '1 . та трябва да направя макро на ексел,
че да я обърне на число. Макрото е готово, но за толкова клетки - отива доста време...
идеята е да се спести това време
1.Ползвам версия 7 на делфито
2.Офис пакета ми е 2003
3.Първото което направих е следния вариант:
ExcelName:='c:\aaa.xls';
Excel:=CreateOleObject('Excel.Application');
Excel.Visible:=False;
Excel.Workbooks.Open(ExcelName);
.... достъпа е по ред колона. Много удобно за писане, но доста по бавно.
Прекрасно за малки таблици
Excel.WorkBooks.close;
Excel.quit;
4.След това минах на варианта
ExcelName:='c:\aaa.xls';
AdoTable1.Active:=false;
ConnStr :='Provider=Microsoft.Jet.OLEDB.4.0;Data Source='+ExcelName +
';Extended Properties="Excel 8.0;HDR=No";Persist Security Info=False';
AdoTable1.ConnectionString:=ConnStr;
DataSource1.DataSet:=AdoTable1;
form1.ADOTable1.TableName:='Sheet1$';
form1.ADOTable1.Active:=true;
form1.DataSource1.DataSet.First;
form1.DataSource1.DataSet.edit;
form1.DataSource1.DataSet.Fields[0].Value:=1;
form1.DataSource1.DataSet.post;
form1.ADOTable1.Active:=false;
Четенето е ред по ред. Повече писане. Но програмчето се ускори с към 90%
(все пак говорим за над 2-3 милиона клетки които се ползват)
Та отвратителното на всичкото това е, че тази тъпа еденица дето я ръгам в А1,
след като отворя ексела си седи като текст -> '1 . та трябва да направя макро на ексел,
че да я обърне на число. Макрото е готово, но за толкова клетки - отива доста време...
идеята е да се спести това време
Re: Делфи чрез АДО в ЕКСЕЛ
Това което съм ти дал като вариант е формат за експорт към Ексел 97-2003 чрез работа с текстов файл. Имам го само на php и затова ти го пратих така.
Първия вариант който си ползвал е по-добър - използваш самия ексел да си генерира файл, недостатък е че трябва да имаш инсталиран офис на всеки комп на който пускаш програмата. За ускоряване - вместо директно писане в клетка и комуникация с ексела е по-добре всички данни да се "изсипят" в един масив:
DataArray:array of array of variant;
...
Ако данните са в TTable
ii:=0;
REPEAT
for jj:=0 to ColCount-1 do
case Table.FieldDefs[jj].DataType of
ftInteger:DataArray[ii,jj]:=Table.Fields[jj].AsInteger;
ftFloat:DataArray[ii,jj]:=Table.Fields[jj].AsFloat;
ftString:
begin
sTemp:=Table.Fields[jj].AsString;
DataArray[ii,jj]:=sTemp;
end;
ftDate:DataArray[ii,jj]:=Table.Fields[jj].AsString;
ftMemo:DataArray[ii,jj]:=Table.Fields[jj].AsString;
else
messagedlg('ii='+inttostr(ii)+' jj='+inttostr(jj),mterror,[mbOK],0);
end;
ii:=ii+1;
Table.Next();
UNTIL Table.Eof;
...
Worksheet.Range['A1',Worksheet.Cells.Item[CurrRowCount,ColCount]].Value :=DataArray;
Така става с пъти по-бързо, спрямо директни обръщения за всяка клетка.
Варианта с php пък е още по-бърз и универсален - не е необходим инсталиран ексел. Но ще трябва да се потрудиш да го преведеш на делфи, напр.:
function XLS_BOF():string;
var
sReturn:string;
begin
sReturn:='';
sReturn:=sReturn + #09+#08+#08+#00+#00+#00+#16+#00+#00+#00+#00+#00;
Result:=sReturn;
end;
Имай предвид, че в php както и в С подредбата старши-младши битове е противоположна от тази в Делфи - оттам е и разликата в превода.
Първия вариант който си ползвал е по-добър - използваш самия ексел да си генерира файл, недостатък е че трябва да имаш инсталиран офис на всеки комп на който пускаш програмата. За ускоряване - вместо директно писане в клетка и комуникация с ексела е по-добре всички данни да се "изсипят" в един масив:
DataArray:array of array of variant;
...
Ако данните са в TTable
ii:=0;
REPEAT
for jj:=0 to ColCount-1 do
case Table.FieldDefs[jj].DataType of
ftInteger:DataArray[ii,jj]:=Table.Fields[jj].AsInteger;
ftFloat:DataArray[ii,jj]:=Table.Fields[jj].AsFloat;
ftString:
begin
sTemp:=Table.Fields[jj].AsString;
DataArray[ii,jj]:=sTemp;
end;
ftDate:DataArray[ii,jj]:=Table.Fields[jj].AsString;
ftMemo:DataArray[ii,jj]:=Table.Fields[jj].AsString;
else
messagedlg('ii='+inttostr(ii)+' jj='+inttostr(jj),mterror,[mbOK],0);
end;
ii:=ii+1;
Table.Next();
UNTIL Table.Eof;
...
Worksheet.Range['A1',Worksheet.Cells.Item[CurrRowCount,ColCount]].Value :=DataArray;
Така става с пъти по-бързо, спрямо директни обръщения за всяка клетка.
Варианта с php пък е още по-бърз и универсален - не е необходим инсталиран ексел. Но ще трябва да се потрудиш да го преведеш на делфи, напр.:
function XLS_BOF():string;
var
sReturn:string;
begin
sReturn:='';
sReturn:=sReturn + #09+#08+#08+#00+#00+#00+#16+#00+#00+#00+#00+#00;
Result:=sReturn;
end;
Имай предвид, че в php както и в С подредбата старши-младши битове е противоположна от тази в Делфи - оттам е и разликата в превода.
Re: Делфи чрез АДО в ЕКСЕЛ
Безкрайно съм ти благодарен за отделеното време.
Програмчето е такова, че ще се стартира най много 2-3 пъти в годината. То ще прехвърля данни в екселския файл, с който ще работи предклавиатурното устройство. Юсера ще пише вътре , може да трие и т.н. При повторно стартиране ще се добавят нови редове (евентуално).
За 2-3 пъти в годината - дали ще се чака 1 или 10 мин - все тая... По важното е да се работи отваря Екселчето по-бързо, а ако там заложа тези преобразувания - ще ми избодат очите!
Колкото до съветите ти:
За Вариант 2 - ЕКСЕЛ е задължително да ма на комп-а, понеще там ще е и юсера и ще си бачка, и няма смисъл да правя конверсии на нещо дето няма да ползвам нататъка.
За Вариант 1 - Не ми се рискува преработка на програмчето, дето вече си бачка... Сигур ще ми отвори още една седмица работа...
Може би още в началото трябваше да си задам въпроса така:
"КАК ДА ЗАПИША ФОРМУЛА В ЕКСЕЛСКА КЛЕТKА, ЧРЕЗ АДО?
Защото "=(B1+B2)" ми го слага текст..."
Ако беше Access - там вида на полето може да се определи предварително (и се определя де) и няма никакъв проблем, ама с тоз тъп ЕКСЕЛ! Даже и да му форматирам предварително клетката - не става. А дали не му е заложено така да е от MS$? Вече не знам какво да мисля...
Ще поровя пак из гуглето...
Програмчето е такова, че ще се стартира най много 2-3 пъти в годината. То ще прехвърля данни в екселския файл, с който ще работи предклавиатурното устройство. Юсера ще пише вътре , може да трие и т.н. При повторно стартиране ще се добавят нови редове (евентуално).
За 2-3 пъти в годината - дали ще се чака 1 или 10 мин - все тая... По важното е да се работи отваря Екселчето по-бързо, а ако там заложа тези преобразувания - ще ми избодат очите!
Колкото до съветите ти:
За Вариант 2 - ЕКСЕЛ е задължително да ма на комп-а, понеще там ще е и юсера и ще си бачка, и няма смисъл да правя конверсии на нещо дето няма да ползвам нататъка.
За Вариант 1 - Не ми се рискува преработка на програмчето, дето вече си бачка... Сигур ще ми отвори още една седмица работа...
Може би още в началото трябваше да си задам въпроса така:
"КАК ДА ЗАПИША ФОРМУЛА В ЕКСЕЛСКА КЛЕТKА, ЧРЕЗ АДО?
Защото "=(B1+B2)" ми го слага текст..."
Ако беше Access - там вида на полето може да се определи предварително (и се определя де) и няма никакъв проблем, ама с тоз тъп ЕКСЕЛ! Даже и да му форматирам предварително клетката - не става. А дали не му е заложено така да е от MS$? Вече не знам какво да мисля...
Ще поровя пак из гуглето...
Re: Делфи чрез АДО в ЕКСЕЛ
Благодаря на всички които си предложиха помоща. Беше ми от огромно значение.
Реших си проблема.
За други , които като мене ще се трепят над същия проблем , ще кажа какво направих:
1.сложих IMEX=0 в ConnectionString-a. Сега изглежда така:
ConnStr := 'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\AAA.XLS;Extended Properties="Excel 8.0;HDR=No;IMEX=0"';
Тез от МS$ са като банките - с малък шрифт , нейде на майната си е обяснено че Microsoft.Jet.OLEDB.4.0 по подразбиране слага само в стринг. IMEX=2 означавало стринг, пък 0 и 2 друго... А защо 0 и 2 , а не само 0.... Бате Бил е замислил сигур нещо занататъка...
2.Сложих празен файл и пуснах едно:
....
DataSource1.DataSet.first;
DataSource1.DataSet.edit;
DataSource1.DataSet.Fields[0].Value:=1;
...
ДА ДА - ама НЕ! Шатна ми го на третия ред чак... и ти като текст
3.Сложих в А1 на ексела антетка ....... Вече почваше писането от 2 ред... Е, един ред загубен - майната му. Ама пак си беше текст тъпата единица...
4.Форматирах А2 от ексела на цяло число с 0 знака и работата заспа.
5.пробвах с форматиране дата и число с 2 знака - ОК
6.Бегам за каса бира че ми пресъхна устата....
Може темата да се заключи!
Реших си проблема.
За други , които като мене ще се трепят над същия проблем , ще кажа какво направих:
1.сложих IMEX=0 в ConnectionString-a. Сега изглежда така:
ConnStr := 'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\AAA.XLS;Extended Properties="Excel 8.0;HDR=No;IMEX=0"';
Тез от МS$ са като банките - с малък шрифт , нейде на майната си е обяснено че Microsoft.Jet.OLEDB.4.0 по подразбиране слага само в стринг. IMEX=2 означавало стринг, пък 0 и 2 друго... А защо 0 и 2 , а не само 0.... Бате Бил е замислил сигур нещо занататъка...
2.Сложих празен файл и пуснах едно:
....
DataSource1.DataSet.first;
DataSource1.DataSet.edit;
DataSource1.DataSet.Fields[0].Value:=1;
...
ДА ДА - ама НЕ! Шатна ми го на третия ред чак... и ти като текст
3.Сложих в А1 на ексела антетка ....... Вече почваше писането от 2 ред... Е, един ред загубен - майната му. Ама пак си беше текст тъпата единица...
4.Форматирах А2 от ексела на цяло число с 0 знака и работата заспа.
5.пробвах с форматиране дата и число с 2 знака - ОК
6.Бегам за каса бира че ми пресъхна устата....
Може темата да се заключи!