繁体   English   中英

Perl 脚本将 xls 转换为 xlsx 正在生成空白 xlsx 和错误消息

[英]Perl script to convert xls to xlsx is generating blank xlsx and error message

执行以下 perl 脚本将 xls 转换为 xlsx,但它通过给出以下错误消息生成空白 xlsx。 请帮助我更正代码。 错误信息:

/usr/local/share/perl5/Spreadsheet/ParseExcel.pm 第 175 行的 hash 分配中的奇数个元素。

#! /usr/bin/perl

use warnings;
use strict;

use Spreadsheet::ParseExcel;
use Excel::Writer::XLSX;

my $excel_xls = Spreadsheet::ParseExcel -> new ('Test.xls');
my ($sheet_xls, $row, $col, $cell);

my $excel_xlsx = Excel::Writer::XLSX->new('Test.xlsx');
my $sheet_xlsx = $excel_xlsx->add_worksheet();


for $sheet_xls ( @{ $excel_xls->{Worksheet} } ) {
    for $row ( $sheet_xls->{MinRow} .. $sheet_xls->{MaxRow} ) {
        for $col ( $sheet_xls->{MinCol} .. $sheet_xls->{MaxCol} ) {
            my $cell = $sheet_xls->{Cells}[$row][$col];
            print "$cell->{Val} ";
            $sheet_xlsx->write($row, $col, $cell->{Val});
        }
        print "\n";
    }
}

也许您应该稍微仔细看看Spreadsheet::ParseExcel 中的new()方法的文档 示例如下所示:

my $parser = Spreadsheet::ParseExcel->new();

$parser = Spreadsheet::ParseExcel->new( Password => 'secret' );

$parser = Spreadsheet::ParseExcel->new(
    CellHandler => \&cell_handler,
    NotSetCell  => 1,
);

该方法不需要参数或键/值对列表。 您对该方法的调用如下所示:

my $excel_xls = Spreadsheet::ParseExcel -> new ('Test.xls');

没有将文件名作为参数的示例。 解析文件是一个两阶段的过程。 您创建一个解析器 object:

my $parser = Spreadsheet::ParseExcel->new();

然后在 object 上使用parse()方法来解析电子表格:

my $excel_xls = $parser->parse('Test.xls');

如果您只解析一个文件,那么您可以将这两行合并为一行:

my $excel_xls = Spreadsheet::ParseExcel->new()->parse('Test.xls');

根据您的新要求(将参数文件路径传递给程序),我添加了必要的代码。 安装(Getopt::Long perl 模块)

use strict;
use warnings;

use Getopt::Long;
use Text::CSV_XS qw( csv );
use Excel::Writer::XLSX;

# get digit from string
sub get_digit {
    my ($string) = @_;
    my ($digit) = $string =~ /(\d+)/;
    return ((defined $digit) ? $digit : '');
}

# write data to excel file
sub write_excel {
    my ($worksheet,$aoa) = @_;
    my $row = 0;
    foreach my $internal_array_ref (@$aoa) {
        my $col=0;
        foreach my $element (@$internal_array_ref) {
            # if element is not having any value
            $element = '' unless defined $element;
            $worksheet->write( $row, $col++, $element );
        }
        $row++;
    }
}

### Main ##
my $csv_file;
my $excel_file;
GetOptions('file=s' => \$csv_file) or die "Usage: $0 --file FILENAME\n";
if (not defined $csv_file) {
    print "\n Argument 'file' is mandatory \n";
    print "for example $0 --file FILEPATH";
    exit 1;
}
# check for file exists and not empty
if (-s $csv_file) {
    # Check for file contain date digit
    my $date_digit = get_digit($csv_file);
    if ($date_digit eq '') {
        print "\n $csv_file not contain date information \n";
        exit 1;
    } else {
        # excel file name with date digit
        $excel_file = "csv_to_excel_$date_digit.xlsx";
        #  Read whole file in memory (as array of array)
        # change seperate char as per your csv file data
        # change quote char as per your csv file data (else just mentioned undef)
        # change escape char as per your csv file data (else just mentioned undef)
        eval {
            my $aoa = csv (in => $csv_file,     
                        encoding => "UTF-8",
                        sep_char    => ',',
                        quote_char  => '"',
                        escape_char => undef);

            if (scalar @$aoa) {
                # Create a new Excel workbook
                my $workbook = Excel::Writer::XLSX->new( $excel_file );
                # Add a worksheet
                my $worksheet = $workbook->add_worksheet();
                # write to excel file
                write_excel($worksheet,$aoa);
                $workbook->close();
                print "\n The $excel_file created sucessfully. \n";
            }
        };

        if ($@) {
            print "\n Invalid CSV file or check CSV file format \n";
            exit 1;
        }
    }
}  else {
    print "\n Please provide valid file path: $csv_file";
    exit 1;
}

output

perl csv_xlsx.pl

 Argument 'file' is mandatory
for example csv_xlsx.pl --file FILEPATH
##############
perl csv_xlsx.pl --file
Option file requires an argument
Usage: csv_xlsx.pl --file FILENAME
#############
perl csv_xlsx.pl --file sample.csv

 sample.csv not contain date information
###############
perl csv_xlsx.pl --file sample_20200609.csv

 The csv_to_excel_20200609.xlsx created sucessfully

根据用户要求,脚本正在执行以下操作。

  1. 将 CSV 数据写入 xlsx 文件
  2. 用户需要提供输入目录路径(其中将出现多个 csv 文件)
  3. 用户需要提供 output 目录(将在其中创建 xlsx 文件)
  4. 脚本正在执行以下验证
    • 如果输入目录未指定为命令行参数,则显示错误
    • 如果 output 目录未指定为命令行参数,则显示错误
    • 检查目录是否存在
    • 检查 csv 文件以及文件名中的时间标签信息
    • 仅处理有效的 csv 文件以创建 xlsx 文件。

代码

use strict;
use warnings;

use Getopt::Long;
# this module helps to read csv data from file
use Text::CSV_XS qw( csv );
# this module helps to create xlsx file
use Excel::Writer::XLSX;
use File::Basename;

# get files from input directory
sub get_files {
    my $dir = shift // '.';
    my @all_files = ();
    opendir my $dh, $dir or die "Could not open '$dir' for reading '$!'\n";
    my @files = readdir $dh;
    foreach my $file (@files) {
        if ($file eq '.' or $file eq '..') {
            next;
        }
        # check for file .csv
        if ((( split /\./, $file )[-1]) eq "csv") {
            # winodws os syntax
            push @all_files, "$dir\\$file";
            # linux os syntax
            #push @all_files, "$dir/$file";
        }
    }
    closedir $dh;
    return @all_files;
}

# get digit from string
sub get_digit {
    my ($string) = @_;
    my ($digit) = $string =~ /(\d+)/;
    return ((defined $digit) ? $digit : '');
}

# write data to excel file
sub write_excel {
    my ($worksheet,$aoa) = @_;
    my $row = 0;
    foreach my $internal_array_ref (@$aoa) {
        my $col=0;
        foreach my $element (@$internal_array_ref) {
            # if element is not having any value
            $element = '' unless defined $element;
            $worksheet->write_string( $row, $col++, $element );
        }
        $row++;
    }
}

### Main ##
my $csv_dir;
my $output_dir;
# command line arguments
# input directory (--idir)which going to contain csv files
# ouput directory (--odir) where xlsx files going to be created
GetOptions(
    'idir=s' => \$csv_dir,
    'odir=s' => \$output_dir,
) or die "Usage: $0 --idir Directory PATH -odir DIRECTORY PATH \n";

# if input directory is not specified  as an input argument, show error
if (not defined $csv_dir) {
    print "\n Argument 'idir' is mandatory \n";
    print "for example $0 --ifile DIRPATH";
    exit 1;
}

# if output directory is not specified as an input argument, show error
if (not defined $output_dir) {
    print "\n Argument 'odir' is mandatory \n";
    print "for example $0 --odir DIRECTORY PATH";
    exit 1;
}

# check for input and output directory path
if ((-d $csv_dir) && (-d $output_dir)) {
    # get all csv files from input directory
    my @csv_files = get_files($csv_dir);
    # read csv file data and create xlsx file
    foreach my $csv_file (@csv_files) {
        # Check for file contain date digit
        my $date_digit = get_digit($csv_file);
        if ($date_digit eq '') {
            print "\n $csv_file not contain date information \n";
        } else {
            # excel file name with date digit
            # get file name from given file path (except extension)
            my $filename = basename("$csv_file",  ".csv");
            # this syntax is for windows to create xlsx file path
            my $excel_file = "$output_dir\\$filename.xlsx";
            # this syntax is for windows to create xlsx file path
            #my $excel_file = "$output_dir/$filename.xlsx";

            #  Read whole file in memory (as array of array)
            # change seperate char as per your csv file data
            # change quote char as per your csv file data (else just mentioned undef)
            # change escape char as per your csv file data (else just mentioned undef)
            eval {
                my $aoa = csv (in => $csv_file,     
                        encoding => "UTF-8",
                        sep_char    => ',',
                        quote_char  => '"',
                        escape_char => undef);

                if (scalar @$aoa) {
                    # Create a new Excel workbook
                    my $workbook = Excel::Writer::XLSX->new( $excel_file );
                    # Add a worksheet
                    my $worksheet = $workbook->add_worksheet();
                    # write csv data to excel file
                    write_excel($worksheet,$aoa);
                    $workbook->close();
                    print "\n The $excel_file created sucessfully. \n";
                }
            };

            if ($@) {
                print "\n Invalid CSV file or check CSV file format \n";
            }
        }
    }
}  else {
    print "\n Please provide valid directiory path: $csv_dir or Please provide valid directory path $output_dir";
    exit 1;
}

Output 和执行语法

### Windows
C:\Users\batman\source\repos>perl csv_xlsx.pl --idir C:\Users\batman\source\repos\csv --odir C:\Users\batman\source\repos\excel_out

 The C:\Users\batman\source\repos\excel_out\sample_dept1_20200609.xlsx created sucessfully.

 The C:\Users\batman\source\repos\excel_out\sample_dept2_20200610.xlsx created sucessfully.

### Linux
perl csv_xlsx.pl --idir /Users/batman/source/repos/csv --odir /Users/batman/source/repos/excel_out

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM