[comp.lang.perl] Write

tbertels@cipc1.Dayton.NCR.COM (Tom Bertelson) (01/18/90)

While working on a Perl program that will move a lot of binary data I
discovered the following in the manual:

	Note that write is NOT the opposite of read.

I can use read and unpack to handle the data coming in, but how can I
get it out again?  I'm currently using 'printf STDOUT "%128s",
$buffer;', but want to use a larger buffer (it writes to a streaming
tape).  Am I missing something obvious, ar am I just out of luck?
-- 
Tom Bertelson			DISCLAIMER:  My opinions are my own and
Tom.Bertelson@Dayton.NCR.COM	in no way reflect those of my employer.
...!uunet!ncrlnk!cipc1!tbertels

lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (01/19/90)

In article <1585@cipc1.Dayton.NCR.COM> tbertels@cipc1.Dayton.NCR.COM (Tom Bertelson) writes:
: While working on a Perl program that will move a lot of binary data I
: discovered the following in the manual:
: 
: 	Note that write is NOT the opposite of read.
: 
: I can use read and unpack to handle the data coming in, but how can I
: get it out again?  I'm currently using 'printf STDOUT "%128s",
: $buffer;', but want to use a larger buffer (it writes to a streaming
: tape).  Am I missing something obvious, ar am I just out of luck?

The reason I haven't added a write of the system call variety is that
it seems that print can already do the same thing.  I needed a read because
normal input is line oriented, but the normal print just puts out how
ever many characters there are.  If your string happens to be 64k long,
then it fwrite()s 64k in one fell swoop.  Hopefully fwrite() is written
smart enough to not copy data it doesn't need to before calling the system
call write().  (Note that a perl read() in fact calls fread() rather than
system call read().  We have to make sure that stdio stays notified
of our current FILE status.)

As for how to make sure your string is 64k (or whatever) long, there
are of course several ways to do it.  You can do padding with either
pack() or "\0" x (64 * 1024 - length($foo));  However, it's probably
better to use the fact that substr() can be used as an lvalue.  Say

	$buf = "\0" x (64 * 1024);
	  (or, much more efficiently, till I optimize the foregoing)
	$buf = "\0" x 1024 x 64;

and then, to set the first n bytes of it:

	substr($buf,0,length($foo)) = $foo;

If you assign to a substr a string that is the same length as that specified
in the 3rd argument, the string is modified in place.  (If it's shorter,
some of the target string may get copied.  If it's longer, the entire
targer string may be copied.)

Things get a little more complicated if the length of $foo may run it
off the end of $buf, but you can figure out how to check for that.

Good luck.  I don't know that I'd be brave enough to try to make a tape
stream in perl, but you're welcome to try.  If your fread() and fwrite()
are implemented to bypass stdio buffers when they can, then you might
actually be able to do it.  If not, you could have problems unless your
CPU really screams.  One of these days when I haven't anything better
to do, I may make perl output cheat on stdio when it can get away with
it, but till then you're at the mercy of your fwrite() implementation.

Just checked--the 4.2 fwrite() stinks--does an extra memory reference on each
byte it copies to the stdout buffer.  The 4.3 fwrite() at least calls bcopy,
but it doesn't appear to call write directly when it can (guessing from
the symbol table here) unless it fiddles the buffer pointer temporarily
and lets flsbuf do the write.  SunOS 4.0.3 appears to call write directly
(again guessing from the symbol table).  Sigh.  Wish I had more source
access, if just for reference...

So, it looks like it depends on your fwrite().  Like the manual says,
perl can do binary, but most of the polish has gone into text processing.

Larry