[comp.lang.perl] How to zero a file

jw@pan.UUCP (Jamie Watson) (12/23/89)

What is the preferred way to zero a file in perl?  In shell scripts I
use "> filename", so in perl I can 'exec "> filename"', but it seems
to me that there should be a way to do this without using exec.

In a similar vein, what is the preferred way to copy a file?  I could
obviously just crank up 'exec "cp old new"', but again I wonder if there
is some "better" way to do this entirely within perl.  Copying a line at
a time, with "while () print" doesn't seem to me to be an ideal solution.

jw

stef@zweig.sun.com (Stephane Payrard) (12/24/89)

In article <891@pan.UUCP> jw@pan.UUCP (Jamie Watson) writes:


   What is the preferred way to zero a file in perl?  In shell scripts I
   use "> filename", so in perl I can 'exec "> filename"', but it seems
   to me that there should be a way to do this without using exec.

   In a similar vein, what is the preferred way to copy a file?  I could
   obviously just crank up 'exec "cp old new"', but again I wonder if there
   is some "better" way to do this entirely within perl.  Copying a line at
   a time, with "while () print" doesn't seem to me to be an ideal solution.


Here is a example program which should answer your questions (tested
on a Sun 4/110 running SunOS 4.0.3 and perl 3.0 patch 8).

No explicit loop: the danger is to run out of memory if copying a big
file.


#! /usr/bin/perl

open(IN,"<$ARGV[0]") || die "can't open $ARGV[0]";
open(OUT,">$ARGV[1]") || die can't open $ARGV[1]";  # create a zero length file
@in=<IN>;   #  read the whole file in the array @in (one entry perl line)
print OUT @in;


--
--
Stephane Payrard -- stef@sun.com -- (415) 336 3726
Sun Microsystems -- 2550 Garcia Avenue --  M/S 16-40 -- Mountain View  CA 94043

                     
                     

lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (12/28/89)

In article <891@pan.UUCP> jw@pan.UUCP (Jamie Watson) writes:
: What is the preferred way to zero a file in perl?  In shell scripts I
: use "> filename", so in perl I can 'exec "> filename"', but it seems
: to me that there should be a way to do this without using exec.

open(ZERO,'> filename') && close ZERO;

If you do this a lot you can always make it a subroutine:

sub zero {
    open(ZERO, "> $_[0]") && close ZERO;
}

&zero('filename');

: In a similar vein, what is the preferred way to copy a file?  I could
: obviously just crank up 'exec "cp old new"', but again I wonder if there
: is some "better" way to do this entirely within perl.  Copying a line at
: a time, with "while () print" doesn't seem to me to be an ideal solution.

There are several ways to do it, depending on what you're optimizing for.

# Most concise without defining a subroutine
# (and probably fastest on huge files)

system 'cp old new';

0.0u 0.2s 0:01 (timed on /etc/termcap, size 165500)

# Most concise without a subprocess, but slurps whole file

open(OLD,'old');
open(NEW,'>new');
print NEW <OLD>;
close NEW;
close OLD;

1.3u 0.6s 0:03

# much less space taken

open(OLD,'old');
open(NEW,'>new');
while (<OLD>) {
    print NEW;
}
close NEW;
close OLD;

0.8u 0.2s 0:02

# more space taken

open(OLD,'old');
open(NEW,'>new');
$/ = "\000";
while (<OLD>) {
    print NEW;
}
close NEW;
close OLD;

1.0u 0.3s 0:02

# fastest

open(OLD,'old');
open(NEW,'>new');
while (read(OLD,$foo,8192)) {
    print NEW $foo;
}
close NEW;
close OLD;

0.1u 0.1s 0:01

# almost as fast, maybe faster on multiple files

open(OLD,'old');
($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size) = stat OLD;
open(NEW,'>new');
read(OLD,$foo,$size);
print NEW $foo;
close NEW;
close OLD;

0.0u 0.3s 0:01

# slowest

open(OLD,'old');
open(NEW,'>new');
select(NEW); $| = 1;
while (($foo = getc(OLD)) ne '') {
    print NEW $foo;
}
close NEW;
close OLD;

66.1u 73.3s 2:39

# weirdest

#!/usr/local/bin/perl -i.bak

symlink('old','new');
@ARGV=('new');
while (<>) {
    print;
}
unlink 'new.bak';

0.8u 0.3s 0:02

Your mileage may vary, depending on how stdio is implemented on your system,
and in particular on how efficient your fread() and fwrite() are.

Larry