执行下面的perl脚本将xls转换为xlsx,但它生成的是空白的xlsx,给出了下面的错误信息。请帮助我纠正代码。错误信息。
在usrlocalshareperl5SpreadsheetParseExcel.pm第175行的哈希赋值中存在奇数元素。
#! /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";
}
}
根据用户需求,该脚本正在执行以下操作。
编码
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;
}
输出和执行语法
### 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
也许你应该稍微仔细看一下。的文件 new()
在Spreadsheet::ParseExcel中的方法。. 这些例子看起来像这样。
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');
没有一个例子是以文件名为参数的。解析一个文件是一个两阶段的过程。你创建一个解析器对象。
my $parser = Spreadsheet::ParseExcel->new();
然后你使用 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;
}
产出
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