Avi_Perl_Beginner has asked for the wisdom of the Perl Monks concerning the following question:

My requirement is to read all.csv files in the format groupid_groupname.csv in a folder. Secondly after reading create two new columns with groupid & groupname and print the constant value fetched above. I have written the code but while using just print it works perfect and shows exact result but when writing to csv file..it goes for a toss. Please advice
use strict; use warnings; use Text::CSV; use Text::CSV_XS; use autodie; print_Filenames_directory(); sub print_Filenames_directory { my @files = <*.csv>; foreach my $file (@files) { open my $in, "+<:encoding(utf8)", $file or die $!; my $csv = Text::CSV_XS->new ({ binary => 1, auto_diag => 1 }); my @name = split _,$file; my $grpid = $name[0]; my $grpname = substr($name[1], 0,-4); my @headers; while (my $row = $csv->getline($in)) { if($.==1) { # Add value to @columns array splice @$row, 0, 0, "Group ID"; splice @$row, 1, 0, "Group Name"; @headers = "@$row\n"; print "@headers"; #$csv->print(@headers); } else { splice @$row, 0, 0, $grpid; splice @$row, 1, 1, $grpname; print "@$row\n"; #$csv->print($in, @$row); + } } # check for errors $csv->eof or $csv->error_diag(); close $in; } }

Replies are listed 'Best First'.
Re: Inserting new column
by hippo (Archbishop) on May 27, 2015 at 10:42 UTC

    You cannot (should not) write to the open file while you are still reading from it. Open a new tempfile, write to that, then once the whole file has been read and written, close both and rename the tempfile as the original file (taking a backup first to be prudent). The alternative is to read the whole file in first, store the results in RAM and then write them all out in one go. HTH.

Re: Inserting new column
by Tux (Canon) on May 27, 2015 at 11:04 UTC

    Too many thing wrong to comment on all. Here is a simplified version which I think does what you want:

    use strict; use warnings; use autodie; use Text::CSV_XS 1.18; print_Filenames_directory (); sub print_Filenames_directory { my $csv = Text::CSV_XS->new ({ binary => 1, auto_diag => 1 }); foreach my $file (glob "*.csv") { open my $fh, "<", $file or die $!; my @name = split m/_/ => $file; my $grpid = $name[0]; my $grpname = substr $name[1], 0, -4; my @headers = ("Group ID", "Group Name", @{$csv->getline ($fh) +}); my @rows; while (my $row = $csv->getline ($fh)) { # update: forgot to remove the two unwanted splice lines push @rows, [ $grpid, $grpname, @$row ]; } close $fh; open $fh, ">", $file or die $!; $csv->say ($fh, \@headers); $csv->say ($fh, $_) for @rows; close $fh; } }

    Enjoy, Have FUN! H.Merijn
      TUX : Thanks a lot...it was excellent one time solution
Re: Inserting new column
by Anonymous Monk on May 27, 2015 at 10:41 UTC

     open my $in, "+<:encoding(utf8)"

    You know utf8 is not the same as UTF-8

     use autodie; ...  or die $!;

    hah :)

     my @name = split _,$file; my $grpid = $name[0] ; my $grpname = substr($name[1], 0,-4);

    see see perlintro#Parentheses for capturing and http://perldoc.perl.org/perlrequick.html#Extracting-matches

    while...if($.==1) ...

    No need to put the first getline into the loop, just do it before the loop

     #$csv->print($in, @$row);

    You need an $outcsv because Modifying an existing file is three steps :)

    1. read old file
    2. create a new file
    3. rename new file to name of old file