Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

read from a file and write into the same file

by Anonymous Monk
on Mar 02, 2008 at 16:48 UTC ( [id://671509]=perlquestion: print w/replies, xml ) Need Help??

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

Hello monks,
I wanted to ask if there is a way of opening a file for reading and then write something into it.
I found this:  open FILE, "+>>test.txt"; and tried:
open FILE, "+>>test.txt"; while(<FILE>) { print $_; print FILE "*****************"; } close FILE;

but it didn't show me anything nor did it print the ***** in the file.
Any ideas?

Replies are listed 'Best First'.
Re: read from a file and write into the same file
by almut (Canon) on Mar 02, 2008 at 17:32 UTC

    As you're opening for append, the file pointer is positioned at the end, so your while(<FILE>) does not read anything ('cos it's already at EOF). And, as your print FILE ... is in the same loop, it doesn't write anything either, because it doesn't execute at all...

    BTW, it's generally a good idea to get into the habit of always error checking with file operations, in particular with open:

    my $filename = "test.txt"; open FILE, "+>>", $filename or die "Couldn't open file '$filename': $! +";

    Update: In short, what I think you want to achieve (read from the beginning, write at the end?) cannot be done that way, because a file handle does not maintain two file pointers... Alternatingly reading one line then writing (inserting) one line doesn't work either, because the write doesn't shift around the later parts of the file. Rather, it simply overwrites at that position, which typically doesn't work well with text files (due to different line lengths).  To observe the effect try opening with "+<".

      The file pointer is not guaranteed to be anything in particular between the open and the first write, IIRC.

        strace-ing the OP's code (where nothing is being written) shows

        ... open("test.txt", O_RDWR|O_APPEND|O_CREAT|O_LARGEFILE, 0666) = 5 _llseek(5, 0, [57], SEEK_END) = 0 ...

        which I would interpret to mean that the file pointer is positioned.

        (_llseek is a Linux-specific syscall)

Re: read from a file and write into the same file
by DigitalKitty (Parson) on Mar 02, 2008 at 20:15 UTC
    Hi Anonymous Monk.

    Perl has numerous file modes from which to select:
    #Open the 'txt' file for reading open FH, '<', "$file_name.txt" or die "Error:$!\n";
    #Open the 'txt' file for writing. Creates the #file_name if it doesn't already exist #and will delete/overwrite a pre-existing file of the same name open FH, '>', "$file_name.txt" or die "Error:$!\n";
    #Open the 'txt' file for appending. Creates the #file_name if it doesn't already exist open FH, '>>', "$file_name.txt" or die "Error:$!\n";
    #Open the 'txt' file for a 'read/write'. #Will not create the file if it doesn't #already exist and will not delete/overwrite #a pre-existing file of the same name open FH, '+<', "$file_name.txt" or die "Error:$!\n";
    #Open the 'txt' file for a 'read/write'. Will create #the file if it doesn't already exist and will #delete/overwrite a pre-existing file #of the same name open FH, '+>', "$file_name.txt" or die "Error:$!\n";
    #Open the 'txt' file for a 'read/append'. Will create #the file if it doesn't already exist and will #not delete/overwrite a pre-existing file #of the same name open FH, '+>>', "$file_name.txt" or die "Error:$!\n";

    A few suggestions:

    Always enable both the strict and warnings pragmas with use strict; and use warnings; respectively. When you perform a file close operation, it is beneficial to check the success or failure since a hardware error could result:
    close FH or die "Error in closing the file ", __FILE__, " $!\n";

    Hope this helps,

    ~Katie
Re: read from a file and write into the same file
by CountZero (Bishop) on Mar 02, 2008 at 19:48 UTC
    From the docs:
    If MODE is '>>', the file is opened for appending, again being created if necessary.
    Adding a '+' doesn't change the position of the file-pointer, so you are already at the end of the file.

    Your while(<FILE>) gets a boolean FALSE and you never enter the loop at all. Remember, the loop-test is done first! If you want to go through the loop at least once, you put the test at the end:

    do { print $_; print FILE "*****************"; } while (<FILE>)
    Of course the first (and only) time through this loop the value of $_ has no relationship with the file being read and it may even contain a value from earlier in your program!

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

Re: read from a file and write into the same file
by chatur (Acolyte) on Mar 03, 2008 at 06:04 UTC
    Hi Anonymous monk

    In my view you want to read all the file and afterwards append to a file then you can do is create a two file handleing pointers.

    First thing is to read the whole content of a file to a memory or simply display it out.

    Afterwards do the appending work.

    Here is the example for the sorting file contents that might help

    #!/usr/bin/perl -w if (@ARGV < 1 ) { print "$0 <file>\n"; exit 1 } $tmp_file=$ARGV[0]; open(TMP_INPUT_FILE, "<$tmp_file"); # open for input my(@lines) = <TMP_INPUT_FILE>; # read file into list close(TMP_INPUT_FILE); open(TMP_OUTPUT_FILE, ">$tmp_file"); @lines = sort(@lines); # sort the list my($line); foreach $line (@lines) # loop thru list { print TMP_OUTPUT_FILE "$line"; # print in sort order } close(TMP_OUTPUT_FILE);


    In the above example filename is supplied at the command line.
      It is considered better to use <code> ... </code> tags rather than <pre> ... </pre> around code. This will allow easy downloading of the code and assures sensible wrapping of overly long line of the code. Also I have a code colorizer which needs <code> ... </code> tags to know what to colorize.

      CountZero

      A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

        Thanks for your comment and updated it
Re: read from a file and write into the same file
by akho (Hermit) on Mar 02, 2008 at 16:54 UTC
    Could you give examples — what the file is and what you want it to be? It is not clear where in the file you want to print etc.

    I'd suggest you just write to another file and then copy the result over the original.

Re: read from a file and write into the same file
by systems (Pilgrim) on Mar 03, 2008 at 10:01 UTC
    Remember you can also use perl to edit files in-place.
    > perl -p -i.bak -e "s/(.*)/$1\n****************/" test.txt
    The above command will append a new line containing **************** after every line in the document.

    Now I have a question for the more experienced Perlers, can I do in-place file substitution from inside a script using just Perl code. Or do I have to execute as a command line? I know I can execute a command line within a Perl script, but what I mean, can I do it otherwise, without going to the command line in any way?

      You can do inplace editing from inside scripts with $^I, which is the equivalent for the -i command line option. It is described in perlvar.

      ... can I do in-place file substitution from inside a script

      If using the feature behind the -i option from within a script is what you mean... yes, you can. You can either put the -i.bak on the shebang line, or set the corresponding $^I special variable (as olus already mentioned). The latter allows a little more flexibility, e.g. you could localise the effects

      #!/usr/bin/perl use strict; use warnings; sub edit_inplace { local @ARGV = @_; local $^I = ".bak"; # local $^I = ""; # no backup file while (<>) { s/(.*)/$1\n****************/; print $_; } } edit_inplace("test.txt");

      BTW, even Perl doesn't do a real in-place edit (i.e. modify the physically-same file). Rather, it opens, then renames (or unlinks, when no backup extension is specified) the original file, then opens a new file with the same name — at least on Unix, where opened files continue to be accessible, even when they're no longer associated with a directory entry  (look at the inode numbers before and after to verify, e.g. with "ls -li").

      It's not entierly clear to me what you are asking, but take a look at Tie::File, it might be what you are looking for.
Re: read from a file and write into the same file
by manimarank (Novice) on Mar 03, 2008 at 10:48 UTC
    Tie::File module is useful for modifying the exist file.
Re: read from a file and write into the same file
by goibhniu (Hermit) on Mar 03, 2008 at 19:49 UTC

    I think OP's problems were sufficiently pointed out. I was wondering if lexical file handles (open my $fh vs. open FILE) might be useful. What I found was that I successfully separated the input filehandle pointer from the output filehandle pointer, but the input filehandle stopped at the original eof instead of moving on through the new file contents. Could some wiser monks explain that to me?

    C:\chas_sandbox>for %f in (a b c d) Do echo %f>>alpha.txt C:\chas_sandbox>echo a 1>>alpha.txt C:\chas_sandbox>echo b 1>>alpha.txt C:\chas_sandbox>echo c 1>>alpha.txt C:\chas_sandbox>echo d 1>>alpha.txt C:\chas_sandbox>perl -le "open my $fh_in, '<', 'alpha.txt'; open my $f +h_out, '>> ', 'alpha.txt';while (<$fh_in>) {chomp;print $fh_out chr(ord($_)+4); l +ast if $_ eq 'v'}" C:\chas_sandbox>type alpha.txt a b c d e f g h


    #my sig used to say 'I humbly seek wisdom. '. Now it says:
    use strict;
    use warnings;
    I humbly seek wisdom.
      ...but the input filehandle stopped at the original eof

      Presumably just the usual Suffering from Buffering. Adding $fh_out->autoflush(1); (after having opened the output file) should make things behave as you expect (fill the file with letters up to 'z').  You also need to load IO::Handle for the autoflush method to be available — i.e. -MIO::Handle if you want to stick with your one-liner :)

      BTW, there is nothing special with lexical filehandles in this regard, the piece of code would work just as well with normal filehandles like IN, OUT.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://671509]
Approved by Corion
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (3)
As of 2024-04-25 12:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found