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 comWin32::OLE mas o resultado é mais lento do que você gostaria.
Solução
Use o métodoRange 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étodoRange, 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.
