Volviendo al problema descrito arriba, supongamos por ejemplo que queremos unir en un sólo archivo excel tres archivos (datos1.xls, datos2.xls y datos3.tab) en uno solo que llamaremos todos_datos.xls . Pues bien, por medio del programa descrito debajo sería tan sencillo como ejecutar en el terminal:
$ ./my_xls_merge.pl todos_datos.xls datos1.xls datos2.xls datos3.tab
Yo lo he probado en Linux y los archivos generados se leen perfectamente con el MS Excel, con la única pega de que se pierden las gráficas que hubiera ya en los archivos de entrada.
El código es el siguiente:
#!/usr/bin/perl -w
# programa 9 my_xls_merge.pl
# programita para unir hojas de diferentes archivos .xls o .tab en un solo libro excel
# OJO: conserva el valor de cada celda de una hoja de calculo, no las formulas,
# y se pierden los diagramas por ejemplo
# inspirado por http://www.perlmonks.org/?node_id=743574
use strict;
use Spreadsheet::ParseExcel;
use Spreadsheet::WriteExcel;
use File::Basename;
my $MAXLENGTHSHEETNAME = 31;
die "# usage: $0 <outfile.xls> <file1.xls> ... <fileN.xls>\n" if(scalar(@ARGV) < 2);
my @infiles = @ARGV;
my $outfile = shift(@infiles);
if(-e $outfile)
{
print "# a file named '$outfile' already exists, overwrite? (Y/N)\n";
my $overwrite = <STDIN>;
if($overwrite ne "Y\n"){ exit }
else{ unlink($outfile) }
}
# instantiate resulting excel object
my $outbook = Spreadsheet::WriteExcel->new($outfile) ||
die "# $0: cannot create '$outfile': $!";
for my $file (@infiles)
{
if(!-e $file)
{
print "# skipping non-existing file '$file'\n";
next;
}
# remove path
my ($filename,$copysheet_name) = (fileparse($file));
my $excel = Spreadsheet::ParseExcel::Workbook->Parse($file);
if(defined($excel->{'File'})) # excel format infiles
{
foreach my $sheet (@{$excel->{Worksheet}})
{
$copysheet_name = $sheet->{'Name'} . '-' . $filename;
if(length($copysheet_name) > $MAXLENGTHSHEETNAME)
{
print "# abbreviating $copysheet_name to ";
$copysheet_name = substr($copysheet_name,0,$MAXLENGTHSHEETNAME-3).'...';
print "$copysheet_name\n";
}
print "# adding '$file' sheet '$sheet->{'Name'}' ($copysheet_name)\n";
my $copysheet = $outbook->add_worksheet($copysheet_name);
$sheet->{'MaxRow'} ||= $sheet->{'MinRow'};
foreach my $row ($sheet->{'MinRow'} .. $sheet->{'MaxRow'})
{
my @rowdata = map { $sheet->{'Cells'}->[$row]->[$_]->{'Val'} }
$sheet->{'MinCol'} .. $sheet->{'MaxCol'};
$copysheet->write($row,0,\@rowdata);
}
}
}
elsif($file =~ /\.tab/)# .tab infiles, seria trivial manejar .csv por ejemplo
{
$copysheet_name = $filename;
print "# adding '$file' no_sheet ($copysheet_name)\n";
my $copysheet = $outbook->add_worksheet($copysheet_name);
open(INTAB,$file) || die "# $0 : cannot read '$file': $!";
while(<INTAB>)
{
chomp($_);
my @tabdata = split(/\t/,$_);
$copysheet->write($.-1,0,\@tabdata);
}
close(INTAB);
}
}
$outbook->close();
print "# outfile: $outfile\n";
Un saludo