Показать сообщение отдельно
Старый 08.06.2006, 14:36   #3  
gl00mie is offline
gl00mie
Участник
MCBMSS
Most Valuable Professional
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,684 / 5788 (200) ++++++++++
Регистрация: 28.11.2005
Адрес: Москва
Записей в блоге: 3
Цитата:
Сообщение от _and
Импорт Excel при последовательном чтении из ячеек работает очень медленно (у меня ~500 ячеек в секунду, таблица из строк в 52 ячейки). Хотелось бы считывать данные построчно - скажем, считывать строку в массив и потом обрабатывать. Такое возможно?
Есть чудесный пример импорта данных через ADO. В частности, я таким образом переделывал импорт номенклатуры из Excel, в результате скорость возрасла чуть ли не на порядок. А если его еще обернуть в красивую формочку, то вообще красота получится. Я для импорта номенклатуры использовал такой вот заточенный под указанную формочку класс:
PHP код:
class Uni_ImportInventFromExcelADO
{
    
COM         cnnExcelrstExcelflds;                       // ADO: Connection, Recordset, Fields
    
LanguageId  languageId;
    
int         iMaxFieldsnStartRownCountLines;
    
str         strFileNamestrSheetName;
}
anytype adoFieldValue(int _iIdxboolean _asString true)
{
    
COM         fld;                                            // ADO: Field
    
;
    
fld flds.Item(_iIdx);
    return (
_asString this.adoStrValueFromExcel(fld.Value(), fld.Type(), true) : this.adoValueFromExcel(fld.Value(), fld.Type()));
}
str adoStrValueFromExcel(COMVariant _valint _typeboolean bDblRound false)
{
#CCADO
    
switch (_type)
    {
        case 
#adDouble:         return num2str(_val.double(),-1,(bDblRound ? 0 : -1),1,0);
        
case #adCurrency:       return num2str(_val.currency(),-1,-1,1,0);
        
case #adDate:           return date2str(_val.date(),123,2,2,2,2,4);
        
case #adBoolean:        return int2str(_val.boolean());
        
case #adVarWChar,
             #adLongVarWChar:   return _val.bStr();
    
}
    return 
'';
}
anytype adoValueFromExcel(COMVariant _valint _type)
{
#CCADO
    
switch (_type)
    {
        
// constants for types recognized by ADO for Excel
        
case #adDouble:         return _val.double();
        
case #adCurrency:       return _val.currency();
        
case #adDate:           return _val.date();
        
case #adBoolean:        return _val.boolean();
        
case #adVarWChar,
             #adLongVarWChar:   return _val.bStr();
    
}
    return 
'';
}
void finalize()
{
    
rstExcel.Close();
    
cnnExcel.Close();
}
// get Excel book active sheet name to use as a table name in select
protected str getExcelSheetName()
{
    
ComExcelDocument_RU Excel;
    
COM                 comDoccomAppSheet;

    if(
strSheetName)                                            // if we've been already called successfully...
        
return strSheetName;
    try
    {
        
Excel = new ComExcelDocument_RU();
        if(
Excel.open(strFileNamefalse))                      // Excel - don't show up
        
{
            
comDoc Excel.getComDocument();
            
comApp comDoc.Application();
            
Sheet  comApp.ActiveSheet();
            
strSheetName Sheet.name();
            
Excel.quitApplication(true);                        // true: Excel - don't ask to save the file
            
Excel.finalize();
        }
    }
    catch (
Exception::Error)
    {
        
Excel.quitApplication(true);
        
Excel.finalize();                                       // get lost anyway
    
}
    catch (
Exception::Internal)
    {
        
Excel.quitApplication(true);                            // emulate try/finally
        
Excel.finalize();
    }
    return 
strSheetName;
}
int getLinesReadCount()
{
    return 
nCountLines;
}
int getRecordCount()
{
#define.MaxRecordWeSupposeToRead(10000)
    
int i #MaxRecordWeSupposeToRead;
    
;
    if(
rstExcel && rstExcel.RecordCount()>=0)
        
rstExcel.RecordCount();
    return 
i;
}
void new(str _fileName int _nStartRow)
{
    
rstExcel    null;
    
cnnExcel    null;
    
nCountLines 0;
    
strSheetName'';
    
strFileName _fileName;
    
nStartRow   _nStartRow;
    
languageId  CompanyInfo::languageId();
}
boolean openFile()
{
#CCADO
// we need at least this number of columns
#define.ExcelIdxMax(8)
#localmacro.ADODBExcelConnectionString
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + %";Extended Properties='Excel 8.0;HDR=Yes;IMEX=1'"
#endmacro
    
boolean ok;
    ;
    
ok = (this.getExcelSheetName() != '');                      // first try to open file via COM
    
if(ok)
    {
        
cnnExcel    = new COM("ADODB.Connection");
        
cnnExcel.connectionString(#ADODBExcelConnectionString(strFileName));
        
cnnExcel.Open();
        
rstExcel    = new COM("ADODB.Recordset");               // #adOpenStatic to be able to read RecordCount
        
rstExcel.Open("SELECT * FROM [" strSheetName "$]"cnnExcel#adOpenForwardOnly);
        // check if we have enough fields to read
        
flds        rstExcel.Fields();
        
iMaxFields  flds.Count() - 1;
        if(
iMaxFields #ExcelIdxMax)
            
ok false;
    }
    return 
ok;
}
boolean importNext()
{
    
InventTable         inv;
    ;

    if(
rstExcel.EOF())                                      // no more data
        
return false;

    
// import using this.adoFieldValue()

    
rstExcel.MoveNext();
    
nCountLines++;
    return 
true;

Соотв., в формочке сначала идет вызов openFile(), для статистики берется общее количество строк getRecordCount() и вызывается importNext(), пока этот метод не вернет false. Градусник на форме можно обновлять по данным getLinesReadCount().
По поводу получения количества записей из ADODB.RecordSet. Для типа курсора adOpenForwardOnly rstExcel.RecordCount() всегда будет возвращать 0. Чтобы получать реальное число записей, надо открывать RecordSet с курсором adOpenStatic, но тогда на большом файле получатся ощутимые тормоза при открытии и лишний расход памяти.

Последний раз редактировалось gl00mie; 08.06.2006 в 14:41.
За это сообщение автора поблагодарили: Gustav (3).