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

Hi All, i think this is probably a very simple question for all you guys but i have been trying to find an answer everywhere.. I have a flat file (.txt) that I am using to store data in the following format $id|$title|$description ..fairly simple. What I want to do is be abled to update a line, I have a form that a user can submit to update details, but I am having problem overwriting the current data. Obviously I only want to update the one line.. Thanks for any help, John

Replies are listed 'Best First'.
Re: Using Files
by btrott (Parson) on Mar 05, 2001 at 00:10 UTC
(dkubb) Re: (2) Using Files w/DBD::CSV
by dkubb (Deacon) on Mar 05, 2001 at 01:26 UTC

    Here's an example showing what you want to do with DBD::CSV:

    #!/usr/bin/perl -w #Define the behaviour of DBI->connect for the entire script $ENV{DBI_DSN} ||= 'DBI:CSV(RaiseError=>1,AutoCommit=>1):'. join ';', "csv_eol=\n", 'csv_sep_char=|', 'csv_quote_char=', 'csv_escape_char='; use strict; use DBI; use CGI; my $statement = q{ UPDATE list SET title = ? , description = ? WHERE id = ? }; my $cgi = CGI->new; #Connect to the data source my $dbh = DBI->connect; $dbh->do( $statement, {}, $cgi->param('title'), $cgi->param('description'), $cgi->param('id'), ); $dbh->disconnect; print $cgi->header, 'Updated List'; __END__

    Note: The above code assumes that your file name is "list". DBD::CSV can only process files without any extension. Also, if this is going into production you might want turn on Taint checking by appending a T to the first line, as well as validating each of the CGI paramters, possibly using HTML::FormValidator, which is my personal favorite for this.

    The great thing about using DBD::CSV is that if you ever switch to using a relational database all the code won't need to change, assuming your schema stays the same. This is why I explicitly define the environment variable $ENV{DBI_DSN} at the top of the script, so that you can easily change it later. Keep in mind this varible globally defines the data source that all the DBI->connect method calls will use, and can be globally set for all your CGI's in Apache's httpd.conf.

    As well, I do suggest you look into relational databases, like MySQL or PostgreSQL. They might be better suited for storing this type of information than a flat file.

Re: Using Files
by tune (Curate) on Mar 04, 2001 at 23:25 UTC
    The most simple solution for you is to open the file and read into a variable, modify your line(s), and rewrite the file.
    Some sample code:
    use CGI; $q = new CGI; $upd_id = $q->param('id'); $upd_title = $q->param('title'); $upd_description = $q->param('description'); open F, "file.txt" or die "Can't open file.txt: $!\n"; while (<F>) { chomp; ($id, $title, $description) = split /\|/; if ($id == $upd_id) { ($title, $description) = ($upd_title, $upd_description); $changed = 1; } $upd_file .= "$id|$title|$description\n"; } close F; if ($changed) { open U, ">file.txt" or die "Can't open file.txt: $!\n"; print U $upd_file; close U; }

    I assumed the user submits the information in separate fields. (they used to in real life:)
    BTW, besides using huge files which can slow this script dramatically, I advise start getting closer to Mysql, or any similar relational database.
    If more user is assumed to access this application, also consider using file locking.

    -- tune

Re: Using Files
by cleen (Pilgrim) on Mar 04, 2001 at 23:45 UTC
    There is one way I can think about doing it now, that would be somthing like this

    open(FILE, "blah"); while (<FILE>) { chomp; push @array,$_; } for( my $i; $i < @array; $i++) { ($id,$title,$description) = split(/\|/, $array[$i]); if ($id = "THE ID THAT YOU WANT TO UPDATE") { splice(@array, $i, 1); push @array, "$newid|$newtitle|$newdescription"; } }
    then just write your array out into a file
    I didnt test this out, so its sorta psuedo-code

    -mark
Re: Using Files
by Ido (Hermit) on Mar 05, 2001 at 02:19 UTC
    What about the -i($^I)?
    {local($^I,@ARGV)=('.bak','file.txt'); while(<>){ #the current line is now in $_, the line in the new edited file is wha +t ever I will print now(to ARGVOUT which is already select()ed) if ($.==$linenumberiwanttochange){ chomp; #edit the line print "$_\n"; #print the edited line }else{print} #leave the other lines with no change } }
Re: Using Files
by Anonymous Monk on Mar 05, 2001 at 00:25 UTC
    Thanks for your help guys, It doesnt seem to work..I forgot to mention that the files have more than one line in them so ill need to just edit the one line and leave the rest intact it seems to be deleting all of them.. This is the input i am getting from a html form : $INPUT{'id'} $INPUT{'title'} $INPUT{'description'} This is the format in the file $INPUT{'id'}|$INPUT{'title'}|$INPUT{'description'}"; I want to edit the line with the id they supply to update the title and description.. im very stuck :( any help would be really appreciated, thanks.
Re: Using Files
by Anonymous Monk on Mar 05, 2001 at 00:39 UTC
    Ok I sorted that problem out , yes ! Thanks for your input all.
    One more problem i am having is that I am using a sort of sign up form, I am including postmasterdiret code in this, I want to send the form data to postmaster direct while still signing them up on my script. Is there any way to do this ?
    Thanks