john.tm has asked for the wisdom of the Perl Monks concerning the following question:

I have a csv file that i open and then sort, i have managed to do this and then save the sorted data to a new file But what i would like, is to open the file and sort and save in the same file, however when i try this i end up with a blank file. here is what i have tried so far.
#!/usr/local/bin/perl use strict; use warnings; open (SORT1, "+>C:\\temp\\SORT.CSV") or die "Cannot open file $!\n"; my @sorted = map {$_->[0]} sort { $a->[6] cmp $b->[6] || $a->[2] cmp $b->[2] || $a->[5] cmp $b->[5] || $a->[9] <=> $b->[9]} map {chomp;[$_,split(/,/)]} <SORT1>; foreach(@sorted) { printf SORT1 "$_\n"; } close (SORT1);

Replies are listed 'Best First'.
Re: sort a csv file then updta the same file
by kennethk (Abbot) on May 28, 2014 at 23:57 UTC
    From Mixing Reads and Writes in perlopentut:
    On the other hand, using a greater-than always clobbers (truncates to zero length) an existing file, or creates a brand-new one if there isn't an old one. Adding a "+" for read-write doesn't affect whether it only works on existing files or always clobbers existing ones.
    You truncate the file before your read. You probably need to use <+ combined with seek to read the file, go back to the beginning, and then rewrite it (untested).
    #!/usr/local/bin/perl use strict; use warnings; open (my $sort_fh, '+<', 'C:\temp\SORT.CSV') or die "Cannot open file +$!\n"; my @sorted = map {$_->[0]} sort { $a->[6] cmp $b->[6] || $a->[2] cmp $b->[2] || $a->[5] cmp $b->[5] || $a->[9] <=> $b->[9]} map {chomp;[$_,split(/,/)]} <$sort_fh>; seek $sort_fh, 0, 0; foreach(@sorted) { printf $sort_fh "$_\n"; }

    Note in the above I've swapped to 3-argument open and lexical file handles. Technically unnecessary, but nice for avoid escaping problems on file names and not having to close file handles.


    #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

      Sir, Please tell me how to sort csv with keeping header line
        What have you tried? What worked? See How do I post a question effectively?. Questions such as this should be posted as independent questions/new threads since they are not pertinent to the immediate conversation.

        If you post your code that reads in your CSV, I can help you sort it. Without that info, your question is ill-defined.


        #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

Re: sort a csv file then update the same file
by Tux (Canon) on May 29, 2014 at 09:36 UTC

    The safe way would to be using a real CSV parser:

    use Text::CSV_XS qw( csv ); my @sorted = sort { $a->[5] cmp $b->[5] || $a->[4] cmp $b->[4] } @{csv (in => "sorted.csv")}; csv (out => "sorted.csv", in => \@sorted);

    Which could be shortcutted to

    csv (in => [ sort { $a->[5] cmp $b->[5] || $a->[4] cmp $b->[4] } @{csv (in => "sorted.csv")}], out => "sorted.csv");

    Enjoy, Have FUN! H.Merijn
Re: sort a csv file then update the same file
by Laurent_R (Canon) on May 29, 2014 at 09:47 UTC
    Other possible ways to do it:

    1. open your file in read mode, sort the content in memory, close the file, and reopen it in write mode;

    2. I usually prefer to keep a copy of the original file, just in case something goes wrong. So I rename the original file (changing the extension to .bak, for example), and then open the renamed original in read mode and write to a new file having the original name (this is basically what the -i command line option does in Perl one-liners). The renamed original file can be deleted at a later point, once it has been verified that everything went right.