'+<' mode for opening files

P

Paul Lalli

Greetings.

I am attempting to understand what is the use of opening files for both
reading and writing. I have read both
perldoc -f open
and
perldoc perlopentut
but I am confused. The above documentation refers to using '+<' mode as
'updating', and suggests -i is a better alternative. That's all well
and good, but I would still like to understand what specifying a mode of
'+<' actually *does*.

For example, a sample input file contains the five lines:
1
2
3
4
5

Executing the following script:
#!/usr/bin/perl
use strict;
use warnings;
open my $fh, '+<', 'input.txt' or die "Cannot open: $!\n";
my $line = <$fh>;
print "Line is: $line";
print $fh "A\n";
__END__

results in output of:
Line is: 1

and the input file now contains:
1
2
3
4
5
1
A

Can someone please explain this result to me? It looks as though perl
appended the file with whatever data I had already read, followed by the
output I actually printed. Is this what is supposed to happen? Is
there a way (using this method of opening a file for simultaneous read &
writes) to just print new data to the file, without printing copies of
any data that's already been read?

Thank you for your time,
Paul Lalli
 
X

xhoster

Paul Lalli said:
Greetings.

I am attempting to understand what is the use of opening files for both
reading and writing.

It is useful for treating files like a big old low-level random-access
array of bytes. You use it in conjuction with seek and tell (or sysseek).

....
Can someone please explain this result to me? It looks as though perl
appended the file with whatever data I had already read, followed by the
output I actually printed. Is this what is supposed to happen?

Whenever you switch between reading and writing, you have to do a "seek".
Otherwise weird crap (like what you observed) will happen.

Is
there a way (using this method of opening a file for simultaneous read &
writes) to just print new data to the file, without printing copies of
any data that's already been read?

my $line = <$fh>;
print "Line is: $line";
seek($fh,0,2); #seek to end of file
print $fh "A\n";
print $fh "B\n";

Xho
 
S

Sherm Pendley

Paul said:
I am attempting to understand what is the use of opening files for both
reading and writing. I have read both
perldoc -f open
and
perldoc perlopentut
but I am confused. The above documentation refers to using '+<' mode as
'updating', and suggests -i is a better alternative. That's all well
and good, but I would still like to understand what specifying a mode of
'+<' actually *does*.

Each file handle has a "cursor" - the current position at which reading and
or writing will take place. The cursor is automatically moved to just past
the end of each read/write to the file.

But, you can also move the cursor manually - have a look at
perldoc -f seek
perldoc -f tell

Say you want to access a specified record in a file of fixed-length records,
read it, make some changes to it, and then write it back without writing
the whole file:

# Assuming an already open $fh, strict, warnings, etc...
seek($fh, $record_size * $record_number, SEEK_SET);
read($fh, $record_data, $record_size);

# ... Do some stuff to $record_data
seek($fh, $record_size * $record_number, SEEK_SET);
print $fh $record_data;

As you can probably see by now, it's not so useful for variable-sized
records like lines of text. It won't automatically resize anything, for
example - if the data you write back is longer than the data you read, it
overwrites the beginning of the next record. The most common use of seek()
for text files is simply to "rewind" back to offset 0, overwriting the
contents of a file you've just finished reading.

It's great for fixed-size records like EDI though.

sherm--
 
G

Gunnar Hjalmarsson

Abigail said:
Really? What version of Perl, and what OS? Because that's wrong. What
should be in the input file is:

1
A
3
4
5

Paul's post surprised me too, but I repeated his result on my W98 box
(perl 5.8.0). On Linux I get the expected result.

Explicitly using seek() produced the expected result on W98 as well.
 
X

xhoster

Abigail said:
//
// results in output of:
// Line is: 1
//
// and the input file now contains:
// 1
// 2
// 3
// 4
// 5
// 1
// A

Really? What version of Perl, and what OS? Because that's wrong. What
should be in the input file is:

1
A
3
4
5

I got the same results as Paul, with:

Summary of my perl5 (revision 5.0 version 8 subversion 0) configuration:
Platform:
osname=linux, osvers=2.4.21-1.1931.2.393.entsmp,
archname=i386-linux-thread-multi uname='linux porky.devel.redhat.com
2.4.21-1.1931.2.393.entsmp #1 smp thu aug 14 14:47:21 edt 2003 i686
i686 i386 gnulinux ' config_args='-des -Doptimize=-O2 -g -pipe
-march=i386 -mcpu=i686 -Dmyhostname=localhost
-Dperladmin=root@localhost -Dcc=gcc -Dcf_by=Red Hat, Inc.
-Dinstallprefix=/usr -Dprefix=/usr -Darchname=i386-linux
-Dvendorprefix=/usr -Dsiteprefix=/usr
-Dotherlibdirs=/usr/lib/perl5/5.8.0 -Duseshrplib -Dusethreads
-Duseithreads -Duselargefiles -Dd_dosuid -Dd_semctl_semun -Di_db
-Ui_ndbm -Di_gdbm -Di_shadow -Di_syslog -Dman3ext=3pm -Duseperlio
-Dinstallusrbinperl -Ubincompat5005 -Uversiononly -Dpager=/usr/bin/less
-isr' hint=recommended, useposix=true, d_sigaction=define
usethreads=define use5005threads=undef useithreads=define
usemultiplicity=define useperlio=define d_sfio=undef
uselargefiles=define usesocks=undef use64bitint=undef use64bitall=undef
uselongdouble=undef usemymalloc=n, bincompat5005=undef


Xho
 
P

Paul Lalli

Abigail said:
Paul Lalli ([email protected]) wrote on MMMMCXCIII September MCMXCIII in
<URL:// and the input file now contains:
// 1
// 2
// 3
// 4
// 5
// 1
// A

Really? What version of Perl, and what OS?

I have access to three perl's:
"This is perl, v5.8.0 built for sun4-solaris"
"This is perl, v5.8.2 built for sun4-solaris-thread-multi"
"This is perl, v5.8.4 built for MSWin32-x86-multi-thread"

All three produce the same result
Because that's wrong. What
should be in the input file is:

1
A
3
4
5

That's what I would expect... and that is what I receive when I seek to
the current position as Xho suggested earlier today. From the
documentation of seek, I would say this is a known issue? <shrug>

Paul Lalli
 
E

Eric Amick

Paul's post surprised me too, but I repeated his result on my W98 box
(perl 5.8.0). On Linux I get the expected result.

Explicitly using seek() produced the expected result on W98 as well.

ANSI C (which underlies PerlIO on some systems) requires a file
positioning call such as seek() when switching from reading to writing
or vice versa, otherwise the result is undefined.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,169
Messages
2,570,918
Members
47,458
Latest member
Chris#

Latest Threads

Top