0

我想用 Perl 将 excel 文件转换为 csv 文件。为方便起见,我喜欢使用模块 File::Slurp 进行读/写操作。我需要它在一个子功能中。

在打印到屏幕时,程序会生成所需的输出,不幸的是,生成的 csv 文件只包含一行分号,字段为空。

这是代码:

#!/usr/bin/perl

use File::Copy;
use v5.14;
use Cwd;
use File::Slurp;
use Spreadsheet::ParseExcel;


sub xls2csv {
    my $currentPath = getcwd();
    my @files       = <$currentPath/stage0/*.xls>;

    for my $sourcename (@files) {
        print "Now working on $sourcename\n";
        my $outFile = $sourcename;
        $outFile =~ s/xls/csv/g;
        print "Output CSV-File: ".$outFile."\n";
        my $source_excel = new Spreadsheet::ParseExcel;
        my $source_book  = $source_excel->Parse($sourcename)
          or die "Could not open source Excel file $sourcename: $!";

        foreach my $source_sheet_number ( 0 .. $source_book->{SheetCount} - 1 )
        {
            my $source_sheet = $source_book->{Worksheet}[$source_sheet_number];

            next unless defined $source_sheet->{MaxRow};
            next unless $source_sheet->{MinRow} <= $source_sheet->{MaxRow};
            next unless defined $source_sheet->{MaxCol};
            next unless $source_sheet->{MinCol} <= $source_sheet->{MaxCol};

            foreach my $row_index (
                $source_sheet->{MinRow} .. $source_sheet->{MaxRow} )
            {
                foreach my $col_index (
                    $source_sheet->{MinCol} .. $source_sheet->{MaxCol} )
                {
                    my $source_cell =
                      $source_sheet->{Cells}[$row_index][$col_index];
                    if ($source_cell) {

                        print $source_cell->Value, ";"; # correct output!

                        write_file( $outFile, { binmode => ':utf8' }, $source_cell->Value, ";" ); # only one row of semicolons with empty fields!
                    }
                }
                print "\n";
            }
        }

    }
}

xls2csv();

我知道这与 write_file 函数中传递的参数有关,但无法修复它。

有人有想法吗?

非常感谢您提前。

4

2 回答 2

1

write_file除非给出选项,否则将覆盖文件append => 1。所以这:

write_file( $outFile, { binmode => ':utf8' }, $source_cell->Value, ";" ); 

将为每个新的单元格值写入一个新文件。但是,它与您对“只有一行分号的空字段”的描述不匹配,因为它应该只有一个分号和一个值。

我对你的这种观点持怀疑态度:"For convenience I like to use the module File::Slurp"。虽然该print语句可以正常工作,但 usingFile::Slurp不能。那怎么方便呢?

如果您仍然想使用,您应该做的write_file是收集所有要打印的行,然后在循环结束时一次打印它们。例如:

$line .= $source_cell->Value . ";";   # use concatenation to build the line
...
push @out, "$line\n";                 # store in array
...
write_file(...., \@out);              # print the array

另一个简单的选择是使用join, 或使用Text::CSV模块。

于 2013-08-31T12:53:59.370 回答
0

好吧,在这种特殊情况下,File::Slurp 确实让我复杂化了。我只是想避免重复自己,这是我在以下笨拙的工作解决方案中所做的:

#!/usr/bin/perl

use warnings;
use strict;
use File::Copy;
use v5.14;
use Cwd;
use File::Basename;
use File::Slurp;
use Tie::File;
use Spreadsheet::ParseExcel;
use open qw/:std :utf8/;

# ... other functions

sub xls2csv {
    my $currentPath = getcwd();
    my @files       = <$currentPath/stage0/*.xls>;
    my $fh;

    for my $sourcename (@files) {
        say "Now working on $sourcename";
        my $outFile = $sourcename;
        $outFile =~ s/xls/csv/gi;
        if ( -e $outFile ) {
            unlink($outFile) or die "Error: $!";
            print "Old $outFile deleted.";
        }
        my $source_excel = new Spreadsheet::ParseExcel;
        my $source_book  = $source_excel->Parse($sourcename)
          or die "Could not open source Excel file $sourcename: $!";

        foreach my $source_sheet_number ( 0 .. $source_book->{SheetCount} - 1 )
        {
            my $source_sheet = $source_book->{Worksheet}[$source_sheet_number];

            next unless defined $source_sheet->{MaxRow};
            next unless $source_sheet->{MinRow} <= $source_sheet->{MaxRow};
            next unless defined $source_sheet->{MaxCol};
            next unless $source_sheet->{MinCol} <= $source_sheet->{MaxCol};

            foreach my $row_index (
                $source_sheet->{MinRow} .. $source_sheet->{MaxRow} )
            {
                foreach my $col_index (
                    $source_sheet->{MinCol} .. $source_sheet->{MaxCol} )
                {
                    my $source_cell =
                      $source_sheet->{Cells}[$row_index][$col_index];
                    if ($source_cell) {
                        print $source_cell->Value, ";";
                        open( $fh, '>>', $outFile ) or die "Error: $!";
                        print $fh $source_cell->Value, ";";
                        close $fh;
                    }
                }
                print "\n";
                open( $fh, '>>', $outFile ) or die "Error: $!";
                print $fh "\n";
                close $fh;
            }
        }

    }
}

xls2csv();

我实际上对此并不满意,因为我经常打开和关闭文件(我有很多文件,很多行)。就性能而言,这不是很聪明。

目前我仍然不知道在这种情况下如何使用 split 或 Text:CSV ,以便将所有内容放入一个数组中并且只打开、写入和关闭每个文件一次。

谢谢你的回答 TLP。

于 2013-08-31T23:13:45.967 回答