Perl Brasil

Pesquisar

Documentação

Planeta

Eventos

Comunidade

r2 - 24 Oct 2007 - AlceuJunior

Como ler arquivos do Excel mais rapidamente

Problema

Você quer ler um arquivo do MS Excel com grande quantidade de registros e colunas com Win32::OLE mas o resultado é mais lento do que você gostaria.

Solução

Use o método Range para obter todos os valores das linhas/colunas de uma só vez.

Discussão

Ao invés de utilizar dois loops dentro do seu programa (um para iterar pelas linhas e outro interno, para cada coluna), ler o conteúdo de cada célula e recuperar os dados das mesmas, é possível obter todos os valores com uma chamada só utilizando o método Range, como mostrado abaixo:

my $excel = Win32::OLE->new( 'Excel.Application', 'Quit' ) or die "Cannot read MS Excel file: $!\n";

$excel_book = $excel->WorkBooks->Open($excel_file);

my $sheet = $excel_book->Worksheets(1);

# finding where the spreadsheet finishes
my $last_row = $sheet->UsedRange->Find(
        {
            What => '*',

# same as xlPrevious from Excel constants
            SearchDirection => 2,

            # same as xlByRows from Excel constants
            SearchOrder => 1
        }
    )->{Row};

print "Processing $last_row rows...";

my @content = $sheet->Range( $first_col . '1:' . $last_col . $last_row )->{Value};

$excel_book->Close(0);

Segue um comparativo, utilizando DProf e dprofpp, entre os dois métodos:

- Lendo células uma a uma:

Total Elapsed Time = 263.6139 Seconds
  User+System Time = 73.22391 Seconds
Exclusive Times
%Time ExclSec CumulS #Calls sec/call Csec/c  Name
 49.5   36.30 35.375 564737   0.0001 0.0001  Win32::OLE::Dispatch
 34.2   25.08 25.082 169420   0.0000 0.0000  Win32::OLE::Tie::Fetch
 21.1   15.49 14.763 564735   0.0000 0.0000  Win32::OLE::DESTROY
 15.3   11.22 93.547      1   11.221 93.546  main::parse_excel
 2.42   1.773 36.731 564736   0.0000 0.0001  Win32::OLE::AUTOLOAD
 1.95   1.427  5.844  87786   0.0000 0.0001  Win32::OLE::Variant::new
 1.21   0.888  0.888 131679   0.0000 0.0000  Win32::OLE::Variant::Date
 1.04   0.764  0.764  43893   0.0000 0.0000  Win32::OLE::Variant::Number
 0.87   0.639 25.721 169420   0.0000 0.0000  Win32::OLE::Tie::FETCH
 0.49   0.360  0.360  43893   0.0000 0.0000  Win32::OLE::Variant::As
 0.08   0.059  0.059 131679   0.0000 0.0000  Win32::OLE::Variant::DESTROY
 0.06   0.047  0.047  43893   0.0000 0.0000  Win32::OLE::Variant::VT_R8
 0.02   0.018  0.018  43893   0.0000 0.0000  Win32::OLE::Variant::VT_DATE
 0.02   0.017  0.314  43893   0.0000 0.0000  Win32::OLE::Variant::__ANON__
 0.02   0.016  0.016      1   0.0160 0.0160  Win32::OLE::new

- Lendo o conteúdo diretamente de um intervalo:

Total Elapsed Time = 11.57211 Seconds
  User+System Time = 6.802119 Seconds
Exclusive Times
%Time ExclSec CumulS #Calls sec/call Csec/c  Name
 43.1   2.938  2.938     16   0.1836 0.1836  Win32::OLE::Tie::Fetch
 41.2   2.803  9.004      1   2.8028 9.0038  main::parse_excel
 19.6   1.339  1.437  87786   0.0000 0.0000  Win32::OLE::Variant::new
 15.1   1.030  1.030 131679   0.0000 0.0000  Win32::OLE::Variant::Date
 13.1   0.893  0.893  43893   0.0000 0.0000  Win32::OLE::Variant::Number
 5.12   0.348  0.348  43893   0.0000 0.0000  Win32::OLE::Variant::As
 2.19   0.149  0.149 219710   0.0000 0.0000  Win32::OLE::Variant::DESTROY
 0.47   0.032  0.032      3   0.0107 0.0106  ActivePerl::Config::BEGIN
 0.24   0.016  0.016      1   0.0160 0.0160  Win32::OLE::Uninitialize
 0.24   0.016  0.016      3   0.0053 0.0053  vars::BEGIN
 0.22   0.015  0.015      1   0.0150 0.0150  Win32::OLE::new
 0.22   0.015  0.015      1   0.0150 0.0150  warnings::BEGIN
 0.22   0.015  0.077      5   0.0030 0.0155  main::BEGIN
 0.00   0.000  0.000      1   0.0000 0.0000  Config::launcher
 0.00   0.000  0.000      1   0.0000 0.0000  Config::fetch_string

É preciso ter cuidado, no entanto, com o consumo de memória: uma vez que o conteúdo todo do arquivo Excel será inserido em um array multidimensional (com referências para outros arrays) o consumo de memória do seu programa será bem maior do que realizar a leitura célula a célula.

Comentários