in reply to What is the point of a+ and w+ when opening files?

G'day Maelstrom,

It seems like you are comparing Perl with some other language. If you tell us what that is, we can probably provide a better answer. Links to (some) "countless guides" would no doubt also help. The following may be sufficient for your needs; if not, please provide the additional information that I've indicated.

Perl uses different tokens for a+, w+, and so on; see "open: About modes".

That documentation agrees with you. Here's an extract (+< corresponds to r+; +> to w+):

"... +< is almost always preferred for read/write updates--the +> mode would clobber the file first."

I don't think the requirement you describe for seek and truncate exists in Perl. Having said that, Perl does have seek(), tell() and truncate().

— Ken

Replies are listed 'Best First'.
Re^2: What is the point of a+ and w+ when opening files?
by Maelstrom (Beadle) on May 18, 2023 at 14:21 UTC
    Hi Ken not sure I understand your reply as I'm not having a specific problem with PERL or disagreeing with a document, just wanting clarification on file handle modes which I imagine is not specific to PERL. I've been a native (if infrequent) speaker of PERL for about 20 years now and have thus lost the ability to compare PERL with one of the saner languages but it's true I began this library out of frustration when I originally went from DOS/Pascal to Unix/Perl. I started polishing it again when I discovered wantarray and the fact I could initiate a hash by passing it an array. On the one hand typing my %hash = file2hash($file) is very satisfying but on the other, testing (defined wantarray) to return a scalar is truly disgusting to anyone that's ever tried to learn PERL by reading it.

    As for the guides a fairly representative one is at https://perlmaven.com/open-to-read-and-write . As you can see seek and truncate are requirements in that use case but it doesn't go on to explain if you can replicate the effect of opening a+ by not doing them (or why you would die with a message about mailboxes but I digress :)

    In any case the replies have somewhat illuminated the case for these weird file modes so I've made them optional parameters to the write_open sub which seems preferable to writing multiple routines.

      Firstly, just to clear up a few things:

      • I thought you were comparing with another language because you wrote w+ instead of +> and a+ instead of +>>.
      • I didn't think you were looking for a problem solution; more of an explanation.
      • I didn't say you were disagreeing with anything; I said that the documentation was agreeing with you.
      • Perl is the language; perl is the program that runs Perl code; PERL is not a thing. :-)

      In https://perlmaven.com/open-to-read-and-write:

      • The file is opened: open my $fh, '+<', $file — position is 0.
      • The first record is read: <$fh> — position is >0.
      • The filehandle is repositioned to the start: seek $fh, 0, 0 — position is 0.
      • The file contents are removed: truncate $fh, 0 — position is 0.
      • New content is added: print $fh $count — position is >0.

      The only reason that seek() was used here was to reposition to the start. Note that truncate() does not change the position. There is no inherent requirement to use seek() or truncate() after opening a file in one of the read/write modes.

      The die() message with "mailbox" is an error; probably a copy-paste typo. Hand-crafting I/O messages is tedious and error-prone. I prefer to leave that task to Perl with the autodie pragma; it's less work for me and it won't produce bogus or incomplete messages; I recommend that you use this too.

      I threw together a short script (read_write_append.pl) to demonstrate the three read/write modes:

      #!/usr/bin/env perl use 5.010; use strict; use warnings; use autodie; { say "\n*** Test +< (r+)"; say 'Open file'; open my $fh, '+<', 'test1.txt'; say 'Position in file: ', tell $fh; say 'Read to end of file'; print while <$fh>; say 'Position in file: ', tell $fh; } { say "\n*** Test +> (w+)"; say 'Open file'; open my $fh, '+>', 'for_del.txt'; say 'Position in file: ', tell $fh; say 'Read to end of file'; print while <$fh>; say 'Position in file: ', tell $fh; } { say "\n*** Test +>> (a+)"; say 'Open file'; open my $fh, '+>>', 'testq.txt'; say 'Position in file: ', tell $fh; say 'Read to end of file'; print while <$fh>; say 'Position in file: ', tell $fh; say 'Write a record'; say $fh 'r'; say 'Position in file: ', tell $fh; say 'Rewind to start of file'; seek $fh, 0, 0; say 'Position in file: ', tell $fh; say 'Read to end of file'; print while <$fh>; say 'Position in file: ', tell $fh; }

      I created some test files:

      ken@titan ~/tmp/pm_11152251_file_rwa $ ls -l *.txt -rw-r--r-- 1 ken None 6 May 19 01:41 for_del.txt -rw-r--r-- 1 ken None 6 May 19 01:16 test1.txt -rw-r--r-- 1 ken None 6 May 19 01:40 testq.txt ken@titan ~/tmp/pm_11152251_file_rwa $ cat test1.txt 1 2 3 ken@titan ~/tmp/pm_11152251_file_rwa $ cat for_del.txt z x c ken@titan ~/tmp/pm_11152251_file_rwa $ cat testq.txt q w e ken@titan ~/tmp/pm_11152251_file_rwa $

      Ran the script:

      ken@titan ~/tmp/pm_11152251_file_rwa $ ./read_write_append.pl *** Test +< (r+) Open file Position in file: 0 Read to end of file 1 2 3 Position in file: 6 *** Test +> (w+) Open file Position in file: 0 Read to end of file Position in file: 0 *** Test +>> (a+) Open file Position in file: 6 Read to end of file Position in file: 6 Write a record Position in file: 8 Rewind to start of file Position in file: 0 Read to end of file q w e r Position in file: 8 ken@titan ~/tmp/pm_11152251_file_rwa $

      Then checked the files again:

      ken@titan ~/tmp/pm_11152251_file_rwa $ ls -l *.txt -rw-r--r-- 1 ken None 0 May 19 01:42 for_del.txt -rw-r--r-- 1 ken None 6 May 19 01:16 test1.txt -rw-r--r-- 1 ken None 8 May 19 01:42 testq.txt ken@titan ~/tmp/pm_11152251_file_rwa $ cat test1.txt 1 2 3 ken@titan ~/tmp/pm_11152251_file_rwa $ cat for_del.txt ken@titan ~/tmp/pm_11152251_file_rwa $ cat testq.txt q w e r ken@titan ~/tmp/pm_11152251_file_rwa $

      I suggest that you play around with that code to test whatever other scenarios might interest you.

      — Ken