Perl читает огромный файл Excel - PullRequest
4 голосов
/ 02 марта 2011

У меня огромный файл xlsx (около 127 МБ), и я хочу прочитать с помощью модуля Spreadsheet::Excel, но я получаю ошибки « Out of Memory» на 2 ГБ ОЗУ . (Обратите внимание, что скрипт отлично работает с небольшими файлами Excel 2007)

Есть ли способ читать файл Excel построчно, не превышая лимит памяти.? В поиске Google я наткнулся 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 ]

5 голосов
/ 22 февраля 2012

Я работаю над новым модулем для быстрого и эффективного чтения файлов Excel xlsx с помощью Perl. Это еще не на 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 .

4 голосов
/ 02 марта 2011

Вы пытались преобразовать XLSX в CSV и прочитать его в виде простого текстового файла?

0 голосов
/ 15 февраля 2017

Решение CSV является хорошим. Но также рассмотрите возможность сохранения в формате xlsb - он часто обеспечивает аналогичное уменьшение размера файла, в то же время предоставляя некоторые возможности Excel. (Оставил бы это как комментарий, но не имел репутации ... пока).

0 голосов
/ 31 августа 2014

Попробуйте это.Предполагая, что вы установили модуль Perl Spreadsheet :: Read, который может определить фактический модуль синтаксического анализатора, который будет использоваться для чтения файла, ниже фрагменты кода читают и печатают ячейку 1-го рабочего листа входной рабочей книги.Вы можете проверить объект $ workbook, чтобы увидеть все параметры, доступные для настройки.Этот модуль может использоваться для чтения файлов в других форматах, таких как "csv", "xls".Вот ссылка на туториал, который мне показался полезным: http://search.cpan.org/~hmbrand/Spreadsheet-Read/Read.pm

ReadData можно настроить, передав параметры.Он имеет много опций из каждых 2 опций, которые «ячеек» и «rc» могут быть использованы для изменения поведения, связанного с чтением файла. По умолчанию обе опции установлены в true.Если «ячейки» имеют значение true, тогда ReadData сохраняет ячейки рабочей книги в хэше в возвращаемом объекте.Если «rc» имеет значение true, тогда ReadData сохраняет ячейки рабочей книги в массиве в возвращаемом объекте.В приведенном ниже фрагменте кода, установив ячейки => 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");
...