

現在、perlのCGIプログラムの中で、Excel-2007ファイル(.xlsx)を読み込んで処理をしています。そのとき、CPANの  
Spreadsheet::XLSX -> new(ファイルパス);  
を使用していますが、10000行以上のファイルであると、上記行の実行だけで１分を超えてしまいます。Webアプリなのでレスポンスが遅いのは致命的です。  
Spreadsheet::XLSX 以外のパッケージで、処理が速いものが無いか探しましたが、まだ見つかっていません。  
それが見つからない場合の代替として、件数が多い場合に上記行を実行しないというロジックも考えていますが、上記行を実行せずに件数を取得する方法を見出せていません。

perlにて、多数行のExcelを高速に読み込む、または高速に件数を取得できる手段があればお教え願います。


CC BY-SA 3.0
2015-08-27T09:43:58.220
14906
2015-08-28T11:28:10.880
11090
question
perl
perlでExcelファイルの行数を取得したい。


ファイル名「hoge.xlsx」の ~~シート名~~ 「sheet1」の行数をとる場合、こんな感じでしょうか。異常系はあまり考慮していないサンプルです。

SpreadSheet::XLSXの超簡易版なので、所要時間は同じぐらいかかってしまうかもしれません。

[code]

    #!/usr/bin/env perl
    use strict;
    use warnings;
    use Archive::Zip;
    
    my $zip = Archive::Zip->new();
    $zip->read('hoge.xlsx') == Archive::Zip::AZ_OK or die;
    my $sheet1 = $zip->memberNamed('xl/worksheets/sheet1.xml') or die;
    my $xml = $sheet1->contents;
    my $rows = 0;
    while ($xml =~ /<row r="(\d+)"/g) {
        $rows = $1 if $rows < $1;
    }
    print $rows, "\n";
    
[/code]

### 追記

argusさんのアドバイスと、Shimizuさんの「シート名を指定したい」という声を反映すると、こんな感じでしょうか。

[code]

    #!/usr/bin/env perl
    use strict;
    use warnings;
    no utf8;
    use Archive::Zip;
    
    my $xlsfile = 'hoge.xlsx';
    my $sheetname = 'ほげシート';
    
    my $zip = Archive::Zip->new();
    $zip->read($xlsfile) == Archive::Zip::AZ_OK or die;
    
    my $rels_xml = ($zip->memberNamed('xl/_rels/workbook.xml.rels') or die)->contents;
    my %rels = ();
    while ($rels_xml =~ /\<Relationship(\s.*?)\/?\>/gs) {
        my $rels_elms = $1;
        $rels_elms =~ /\sTarget="(.*?)"/ or next;
        my $path = $1;
        $rels_elms =~ /\sId="(.*?)"/s or next;
        $rels {$1} = $path;
    }
    
    my $book_xml =($zip->memberNamed('xl/workbook.xml') or die)->contents;
    my $rid;
    while ($book_xml =~ /\<sheet(\s.*?)\/\>/gs) {
        my $book_elms = $1;
        if ($book_elms =~ /\sname="$sheetname"/so) {
            $book_elms =~ /\sr:id="([^"]+)"/s or die;
            $rid = $1;
            last;
        }
    }
    $rid or die;
    
    my $sheet = $zip->memberNamed("xl/$rels{$rid}") or die;
    $sheet->contents =~ /<dimension\s+ref="[A-Z]+(\d+):[A-Z]+(\d+)">/s or die;
    print $2 - $1 + 1, "\n";
    
[/code]


CC BY-SA 3.0
2015-08-27T13:36:11.650
14910
2015-08-28T11:28:10.880
2015-08-28T11:28:10.880
4010
4010
14906
answer