Perl阅读巨大的excel文件

时间:2011-03-02 05:14:05

标签: perl excel spreadsheet

我有一个巨大的xlsx文件(大约127 MB),想要使用Spreadsheet::Excel模块阅读,但我在2GB RAM机器上遇到“ Out of Memory”错误。 (注意脚本适用于较小的excel 2007文件)

有没有办法在不达到内存限制的情况下逐行读取excel文件。搜索谷歌我遇到了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();

4 个答案:

答案 0 :(得分:5)

我正在开发一个新模块,用于使用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

答案 1 :(得分:4)

您是否尝试将XLSX转换为csv并将其作为纯文本文件读取?

答案 2 :(得分:0)

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

可以通过传递选项来配置ReadData。它有两个选项,其中有两个选项,即“单元格”,“rc”可用于修改与文件读取相关的行为。默认情况下,两个选项都设置为true。如果“cells”为true,则ReadData将工作簿的单元格存储在返回对象的散列中。如果“rc”为true,则ReadData将工作簿的单元格存储在返回对象的数组中。在下面的代码片段中,通过设置cells =&gt; 0,工作表的内容不会以返回的$ workbook对象的散列格式存储,从而节省了一些内存空间。默认情况下,此选项为true,即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");

答案 3 :(得分:0)

csv解决方案很好。但也考虑保存为xlsb - 它通常会提供类似的文件大小缩小,同时允许一些excel功能。 (会发布这个作为评论,但还没有声誉......)。