Perl读取巨大的Excel文件

我有一个巨大的xlsx文件(约127 MB),并希望阅读使用Spreadsheet::Excel模块,但我在2GB内存机器上出现内存不足”错误 。 (请注意,脚本对较小的Excel 2007文件可以正常工作)

有什么办法可以逐行读取excel文件,而不会触及内存限制。 search谷歌我遇到http://discuss.joelonsoftware.com/default.asp?joel.3.160328.14但我不熟悉如何将电子表格存储到标量。 有人可以给我一个阅读excel 2007文件作为标量和打印单元格值的例子。 以下是我在较小的电子表格上运行的当前脚本。

 #!/usr/bin/perl use Excel::Writer::XLSX; use Spreadsheet::XLSX; my $workbook = Excel::Writer::XLSX->new('Book1.xlsx'); my $worksheet = $workbook->add_worksheet(); # use strict; my $excel = Spreadsheet::XLSX -> new ('Book2.xlsx'); my $date_format = $workbook->add_format(); $date_format->set_num_format('dd/mm/yy hh:mm'); # Columns of interest @columns=(0,1,2,5,9,10,12,13,31); @reportlist=("string1","String2","String3"); @actuallist=("ModifiedString1","ModifiedString2","ModifiedString3"); $max_list=$#reportlist; foreach my $sheet (@{$excel -> {Worksheet}}) { printf("Sheet: %s\n", $sheet->{Name}); $sheet -> {MaxRow} ||= $sheet -> {MinRow}; foreach my $row ($sheet -> {MinRow} .. $sheet -> {MaxRow}) { $sheet -> {MaxCol} ||= $sheet -> {MinCol}; for ($c=0;$c<=$#columns;$c++){ $col=$columns[$c]; my $cell = $sheet -> {Cells} [$row] [$col]; if($col==0){ $cell->{Val}=~ s/\ GMT\+11\:00//g; $worksheet->write($row,$c,$cell->{Val},$date_format); } if ($cell) { $worksheet->write($row,$c,$cell -> {Val}); for($z=0;$z<=$#reportisplist;$z++){ if(($cell->{Val})=~ m/$reportlist[$z]/i){ $worksheet->write($row,$c,$actuallist[$z]); } } } } } } $workbook->close(); 

我正在开发一个新的模块,用于快速和高效地使用Perl读取Excel xlsx文件。 它不在CPAN上(它需要更多的工作),但是你可以在GitHub上获得它。

这是一个如何使用它的例子:

 use strict; use warnings; use Excel::Reader::XLSX; my $reader = Excel::Reader::XLSX->new(); my $workbook = $reader->read_file( 'Book1.xlsx' ); if ( !defined $workbook ) { die $reader->error(), "\n"; } for my $worksheet ( $workbook->worksheets() ) { my $sheetname = $worksheet->name(); print "Sheet = $sheetname\n"; while ( my $row = $worksheet->next_row() ) { while ( my $cell = $row->next_cell() ) { my $row = $cell->row(); my $col = $cell->col(); my $value = $cell->value(); print " Cell ($row, $col) = $value\n"; } } } __END__ 

更新 :这个模块从来没有达到CPAN质量。 试试Spreadsheet :: ParseXLSX 。

你有没有尝试将XLSX转换为CSV文件并将其作为纯文本文件读取?

试试这个。 假设您已经安装了Spreadsheet :: Read perl模块,它可以确定用于读取文件的实际parsing器模块,下面的代码片段将读取并打印input工作簿的第一个工作表的单元格。 您可以检查$ workbook对象以查看可用于configuration的所有选项。 这个模块可以用来读取其他格式的文件,比如“csv”,“xls”。 这里是我发现有用的教程链接: http : //search.cpan.org/~hmbrand/Spreadsheet-Read/Read.pm

ReadData可以通过传递选项来configuration。 它有两个选项中的许多选项,它们是“单元格”,“rc”可以用来修改与文件读取有关的行为。默认情况下,这两个选项都设置为true。 如果“单元格”为true,则ReadData将工作簿的单元格存储在返回对象的散列中。 如果“rc”为true,则ReadData将工作簿的单元格存储在返回对象的数组中。 在下面的代码片段中,通过设置cells => 0,工作表内容将不会以散列格式存储在返回的$ workbook对象中,从而在内存中节省一些空间。 默认情况下,这个选项是正确的,即1等等。 另外为了进一步防止读取完整的文件,可以将选项“rc”设置为false。

 use Spreadsheet::Read; ############################################################################ # function input : file in xlsx format with absolute path # function output : prints 1st worksheet content if exist ############################################################################ sub print_xlsx_file{ my $file_path = shift; my $workbook = ReadData($file_path,cells => 0 ); if(defined $workbook->[0]{'error'}){ print "Error occurred while processing $file_path:". $workbook->[0]{'error'}."\n"; exit(-1); } my $worksheet = $workbook->[1]; my $max_rows = $worksheet->{'maxrow'}; my $max_cols = $worksheet->{'maxcol'}; for my $row_num (1..($max_rows)) { for my $col_num (1..($max_cols)){ print $worksheet->{'cell'}[$col_num][$row_num]."\n"; } } } # call above function # print_xlsx_file("/home/chammu/mybook.xlsx"); 

csv解决scheme是一个很好的解决scheme。 但也可以考虑保存为xlsb – 它会经常提供类似的文件大小缩小,同时允许一些excelfunction。 (会发布这个评论,但没有声誉…)。