HI I have a master spreadsheet with 60 columns, which is updated with new data from an updates file. The new data can be whole new lines or just cells. luckily i came across your site and found an excellent script which does exactly what i want, the only problem i have, is in my case i reference column 'B' in my master file to see if any new data fields need updating, where as in the script on your site the reference ($username) is in column A. the problem i have is when i output the new file i cannot get the columns back in order, ie the column 'B' is always the 1st column, i can't get it back in the original order. column A column B etc. as you will see from my script i can only get output column B A B C D etc.. Could someone advice me where i am going wrong.
Thanks in anticipation.
#!/usr/bin/perl
use strict;
use warnings;
#use diagnostics;
use 5.10.0; # use for smart matching '~~'
use Tk::DirTree;
use Cwd;
use Spreadsheet::BasicRead;
my $fhmaster = "C:\\Temp\\NCPS_Data\\school_data.xlsx";
my $fhmastercsv = "C:\\Temp\\NCPS_Data\\Mre_temp\\master_file.csv";
open( OUTPUT1, '>', "$fhmastercsv" ) or die "unable to open $fhmastercsv !\n Does it Exist ?\n";
my $fhupdatescsv = "C:\\Temp\\NCPS_Data\\Mre_temp\\upload_file.csv";
open( OUTPUT2, '>', "$fhupdatescsv" ) or die "unable to open $fhupdatescsv !\n Does it Exist ?\n";
#====================== master file =====================================================================
my @csvmaster;
if ( -e $fhmaster ) {
my $ss = new Spreadsheet::BasicRead($fhmaster) or die;
my $col = '';
my $row = 0;
while ( my $data = $ss->getNextRow() ) {
$row++;
$col= join( "\t", @$data );
push @csvmaster, $col . "\n" if ( $col ne "" );
}
}
my @arrymstr;
my %seenmstr;
my $Header_mstr = shift (@csvmaster);
foreach (@csvmaster){
chomp (@csvmaster);
$_ = uc $_ ;
$_ =~ s/,//g; #removes commas
$_ =~ s/\t/,/g; #change from tab to csv
print OUTPUT1 $_ . "\n" if !$seenmstr{$_}++ ; #remove any dupes
}
#===================== update file ======================================================================
my $bmw = new MainWindow;
$bmw->withdraw;
$bmw -> focusForce;
my $ok = 1;
my $logo = "C:\\perl\\Mre\\Images\\tk.bmp"; # 32x32 GIF or BMP
my $icon = $bmw->Photo(-file => $logo);
$bmw->idletasks;
$bmw->iconimage($icon);
my $f = $bmw->Frame->pack();
my @types =
(["All files", '*'],["Log files", [qw/.txt .log/]]
);
my $fhupdates = $bmw->getOpenFile();
$fhupdates ="" if(!$fhupdates);
$fhupdates =~ s/\s+$//;
$fhupdates =~ s/\//\\\\/ig;
$f->Button(-text => 'Ok',
-command => sub { $ok = 1 })->pack(-side => 'left');
$f->Button(-text => 'Cancel',
-command => [\&Cancel_buttons] )->pack(-side => 'left');
#--------------------------------------------------------------------------------------------------------------
my @csvupdate;
if ( -e $fhupdates ) {
my $ss = new Spreadsheet::BasicRead($fhupdates) or die;
my $col = '';
my $row = 0;
while ( my $data = $ss->getNextRow() ) {
$row++;
$col= join( "\t", @$data );
push @csvupdate, $col . "\n" if ( $col ne "" );
}
}
my @arryupdte;
my %seenupdte;
my $Header_updte = shift (@csvupdate);
foreach (@csvupdate){
chomp(@csvupdate);
$_ = uc $_ ;
$_ =~ s/,//g; #removes commas
$_ =~ s/\t/,/g; #change from tab to csv
print OUTPUT2 $_ . "\n" if !$seenupdte{$_}++ ; #remove any dupes
}
close OUTPUT1;
close OUTPUT2;
# compare both files and update master with an new data
our $user_and_attr_ref = {}; # intialize hash reference
open my $fh, '<', "C:\\Temp\\NCPS_Data\\Mre_temp\\master_file.csv" or die "can't open file Mre_temp\\master_file.csv ";
foreach (<$fh>) {
chomp;
my ( $classnme ,$childnme, $gender, $classyr ) = split /,/, $_, 4;
$classnme="" if(!$classnme);
$childnme="" if(!$childnme);
$gender="" if(!$gender);
$classyr="" if(!$classyr);
# use username as a key in the hash of Array
push @{ $user_and_attr_ref->{$childnme} }, qq{$classnme,$childnme, $gender,$classyr};
}
close $fh or die "can't close file: Mre_temp\\master_file.csv";
my $file = "C:\\Temp\\NCPS_Data\\Mre_temp\\upload_file.csv";
#return two files, using a subroutine file_outputs
my ( $output_file1, $output_file2 ) = file_outputs($file);
#using an anonymous hash reference in a subroutine write_out_new_file
# twice, file variable, filename and a subroutine reference was passed
write_out_new_file(
{
file => $output_file1,
filename => "C:\\Temp\\NCPS_Data\\Mre_temp\\new_file.csv",
code => \&check_file_to_write,
}
);
# my ( $output_file2 ) = file_outputs($file);
write_out_new_file(
{
file => $output_file2,
filename => "C:\\Temp\\NCPS_Data\\Mre_temp\\changed_file.csv",
code => sub { return $_[0]; },
}
);
sub file_outputs {
my ($filename) = @_;
my ( $new_master_file_str, $update_file_str ) = ( q{}, q{} ); # q{} means ''
open my $fh, '<', $filename or die "can't open file $filename ";
foreach (<$fh>) {
chomp;
my ( $classnme, $childnme, $gender, $classyr ) = split /,/, $_, 4;
$classnme="" if(!$classnme);# I do this so warnings will not complain
$childnme="" if(!$childnme);
$gender="" if(!$gender);
$classyr="" if(!$classyr);
$_ = uc $_ for $classnme, $childnme, $gender;
$_ ||= '' for $classnme, $childnme, $gender;
if ( exists $user_and_attr_ref->{$childnme} ) {
my @user_data_in_upload_file = qq{$classnme, $childnme, $gender,$classyr};
my @user_data_in_master_file =
grep { $_ } values @{ $user_and_attr_ref->{$childnme} };
if ( @user_data_in_upload_file ~~ @user_data_in_master_file ) {
$new_master_file_str .= qq{$classnme,$childnme,$gender,$classyr} . $/;
}
}
else {
$update_file_str .=
qq{$classnme,$childnme,$gender,$classyr,NEW} . $/;
$new_master_file_str .=
qq{$classnme,$childnme,$gender,$classyr} . $/;
}
}
return $new_master_file_str, $update_file_str if wantarray;
}
sub write_out_new_file {
my ($file) = @_;
open my $fh, '>', $file->{'filename'} or die "can't open file \n Does it Exist !\n";
print {$fh} $file->{'code'}->( $file->{'file'} );
}
sub check_file_to_write {
my $new_user_and_attr_ref = {}; #initialize a hash reference
foreach ( split "\n", $_[0] ) {
my ( $classnme, $childnme, $gender, $classyr ) = split /,/, $_, 4;
push @{ $new_user_and_attr_ref->{$childnme} }, qq{$classnme, $childnme, $gender,$classyr};
}
my @key = sort keys %$user_and_attr_ref;
for (@key) {
if ( !exists $new_user_and_attr_ref->{$_} ) {
push @{ $new_user_and_attr_ref->{$_} },
@{ $user_and_attr_ref->{$_} }, $/;
}
}
my $file = q{};
foreach my $sorted_data ( sort keys %$new_user_and_attr_ref ) {
$file .= sprintf "%s,%s\n", $sorted_data,
@{ $new_user_and_attr_ref->{$sorted_data} };
}
return $file;
}
close $file;