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

hi Monks , I have a file that contains employees information which look like this :
EmpInfo ------- John #4 - sleep too much - came late on 04/04/04 - not shaved on 03/03/04 Kim #45 - good job - comes early Mike #3 - not nice
I am just reading the name and comments as arguments then appending it to the file:
my $nameOfEmp; my $comments; open (DATA, "EmpInfo") or die "can't open file\n"; while (my $line = <DATA> ){ if /^$nameOfEmp { next if /^\-; print DATA $comments; } }
My problem is , I am not sure how to append the correct line, if a new comments to be added for John , example "He is too fat" then I need the file to look like this:
EmpInfo ------- John #4 - sleep too much - came late on 04/04/04 - not shaved on 03/03/04 - He is too fat Kim #45 - good job - comes early Mike #3 - not nice
excuse my question , I am new to perl . thanks

Replies are listed 'Best First'.
•Re: Append to correct place in a file
by merlyn (Sage) on Apr 15, 2004 at 15:54 UTC
Re: Append to correct place in a file
by davido (Cardinal) on Apr 15, 2004 at 16:28 UTC
    With flat files, you have a couple of options:

    • You can open the file for appending. ...but then you will write at the end of the file. And if you use seek and tell to write elsewhere, then you overwrite what's already there.
    • You can open the file for writing. ...but then you obliterate the entire contents of the existing file.

    Neither of these outcomes are what you want. For that reason, you have to implement one of several more appropriate strategies:

    • You can open the file for reading, open a temp file for writing, and line by line read through the file and write it back out to the tempfile. When you arrive at the position where you want to insert data, write out that inserted data, and then continue writing out the remainder of the file's contents until the temp file contains an exact copy of the master file plus the inserted line. Then close both files and use rename to rename the tempfile over the master file's name. This approach doesn't scale well if you have lots of inserts to be doing and the file becomes quite large.

    • You can use Tie::File to treat the file like an array, and as merlyn stated, "splice to your heart's content". This approach also doesn't scale well if there are lots of inserts. But if your file really isn't going to grow terribly large, and you're not really concerned with speed, this is a very convenient and simple approach.

    • Another approach is to always just append, but when you do so, append in the form of "employee name: comment". Then when you read the file back in, there will be multiple comments on a given employee name, and the comments may be interspersed in multiple places throughout the file. That's not a problem if you retrieve the employee name into a hash key whos value is a reference to an anonymous array containing all of the comments. You just scan through the file and find all of the comments prefixed with a particular employee's name. This again doesn't scale real well, but at least for insertion is faster than the previous two methods. And even if the file gets pretty big, it shouldn't take terribly long to scan through it for all of the comments attributed to a particular employee.

    • The most scalable solution would be to adopt a database approach. And for simplicity in this respect, you might consider DBI along with DBD::SQLite. DBD::SQLite is a great little database implementation encased in a single module. It's easy to install, and not as intimidating as installing a database with a daemon. With this solution INSERTS won't be as inefficient as they are with flat files, and SELECTS (queries) will be very fast.

    I hope this gives you some ideas to work with.


    Dave

Re: Append to correct place in a file
by meredith (Friar) on Apr 15, 2004 at 16:29 UTC

    Here's the long way -- I'm building a data structure:

    #!/usr/bin/perl use warnings; use strict; open (DATAIN, "EmpInfo") or die "Can\'t open file EmpInfo: $!"; #### try to parse file into a structure my ($cur_emp, @cur_notes); my %EmpInfo; while (<DATAIN>) { my $line = $_; chomp $line; next if $line eq ""; unless ($line =~ /^\-\ (.*)$/) { $EmpInfo{$cur_emp} = [ @cur_notes ] if $cur_emp; $cur_emp = $line; #move to next employee @cur_notes = (); #clear notes list with extreme prejudice } elsif ($cur_emp) { push @cur_notes, $1; } else { warn "note without a current employee? crap!"; } } $EmpInfo{$cur_emp} = [ @cur_notes ]; #get that last one close DATAIN; #### add our comment push @{ $EmpInfo{"John #4"} }, "He is too fat"; #### and send to stdout foreach (sort keys %EmpInfo) { print "$_\n"; foreach (@{ $EmpInfo{$_} }) { print "- $_\n"; } }

    As you can see, the bulk of the code is in parsing your file. If you can, try to come up with a more functional data format. There are many simplistic configuration file formats on CPAN that would probably suit nicely. It'll make things much nicer in the future. In case you're confused about my data structure, %EmpInfo, see perldsc for some info.



    mhoward - at - hattmoward.org
Re: Append to correct place in a file
by Thelonius (Priest) on Apr 15, 2004 at 16:17 UTC
    The easiest way is to rewrite the file with the "-i" command line option.

    perl -i.bak EmpInfo

    Program:

    my $nameOfEmp = "whatever"; my $comments ="whatever"; my $found=0; while (<>){ if ($found) { if (!/^-/) { print $comments; $found = 0; } } elsif (/^$nameOfEmp/o) { $found = 1; } print; } print $comments if $found;
Re: Append to correct place in a file
by waswas-fng (Curate) on Apr 15, 2004 at 16:42 UTC
    I feel sorry for the work environment that keeps employee metrics like this data. =)

    John #4 - sleep too much - came late on 04/04/04 - not shaved on 03/03/04 - He is too fat Kim #45 - good job - comes early Mike #3 - not nice


    -Waswas

      No kidding. To paraphrase an old Dilbert cartoon, "I don't want to work for you - I think I can make more money suing you".

Re: Append to correct place in a file
by simonm (Vicar) on Apr 15, 2004 at 15:56 UTC
    If you want to insert text in the middle of a file, you typically have to re-write it; if you try just printing to the file, the later lines will be overwritten, not automatically pushed back to make room.