[svn:perlfaq] r10981 - perlfaq/trunk
[email protected] Sun, 23 Mar 2008 07:21:02 -0700 (PDT)
| Newsgroups | perl.cvs.perlfaq |
|---|---|
| Message-ID | <[email protected]> |
Author: comdog
Date: Sun Mar 23 07:21:00 2008
New Revision: 10981
Modified:
perlfaq/trunk/perlfaq5.pod
Log:
* perlfaq5: How do I flush/unbuffer an output filehandle? Why must I do this?
+ replaced answer to get to specifics quickly and show example programs
+ added an example using the :unix IO layer
Modified: perlfaq/trunk/perlfaq5.pod
==============================================================================
--- perlfaq/trunk/perlfaq5.pod (original)
+++ perlfaq/trunk/perlfaq5.pod Sun Mar 23 07:21:00 2008
@@ -10,56 +10,88 @@
=head2 How do I flush/unbuffer an output filehandle? Why must I do this?
X<flush> X<buffer> X<unbuffer> X<autoflush>
-Perl does not support truly unbuffered output (except insofar as you
-can C<syswrite(OUT, $char, 1)>), although it does support is "command
-buffering", in which a physical write is performed after every output
-command.
-
-The C standard I/O library (stdio) normally buffers characters sent to
-devices so that there isn't a system call for each byte. In most stdio
-implementations, the type of output buffering and the size of the
-buffer varies according to the type of device. Perl's C<print()> and
-C<write()> functions normally buffer output, while C<syswrite()>
-bypasses buffering all together.
-
-If you want your output to be sent immediately when you execute
-C<print()> or C<write()> (for instance, for some network protocols),
-you must set the handle's autoflush flag. This flag is the Perl
-variable C<$|> and when it is set to a true value, Perl will flush the
-handle's buffer after each C<print()> or C<write()>. Setting C<$|>
-affects buffering only for the currently selected default filehandle.
-You choose this handle with the one argument C<select()> call (see
-L<perlvar/$E<verbar>> and L<perlfunc/select>).
+(contributed by brian d foy)
-Use C<select()> to choose the desired handle, then set its
-per-filehandle variables.
+You might like to read Mark Jason Dominus's "Suffering From Buffering"
+at U<http://perl.plover.com/FAQs/Buffering.html> .
- $old_fh = select(OUTPUT_HANDLE);
- $| = 1;
- select($old_fh);
+Perl normally buffers output so it doesn't make a system call for every
+bit of output. By saving up output, it makes fewer expensive system calls.
+For instance, in this little bit of code, you want to print a dot to the
+screen for every line you process to watch the progress of your program.
+Instead of seeing a dot for every line, Perl buffers the output and you
+have a long wait before you see a row of 50 dots all at once:
+
+ # long wait, then row of dots all at once
+ while( <> ) {
+ print ".";
+ print "\n" unless ++$count % 50;
+
+ #... expensive line processing operations
+ }
-Some modules offer object-oriented access to handles and their
-variables, although they may be overkill if this is the only thing you
-do with them. You can use C<IO::Handle>:
+To get around this, you have to unbuffer the output filehandle, in this
+case, C<STDOUT>. You can set the special variable C<$|> to a true value
+(mnemonic: making your filehandles "piping hot"):
+
+ $|++;
+
+ # dot shown immediately
+ while( <> ) {
+ print ".";
+ print "\n" unless ++$count % 50;
+
+ #... expensive line processing operations
+ }
- use IO::Handle;
- open my( $printer ), ">", "/dev/printer"); # but is this?
- $printer->autoflush(1);
+ The C<$|> is one of the per-filehandle special variables, so each
+ filehandle has its own copy of its value. If you want to merge
+ standard output and standard error for instance, you have to unbuffer
+ each (although STDERR might be unbuffered by default):
-or C<IO::Socket> (which inherits from C<IO::Handle>):
+ {
+ my $previous_default = select(STDOUT); # save previous default
+ $|++; # autoflush STDOUT
+ select(STDERR);
+ $|++; # autoflush STDERR, to be sure
+ select($previous_default); # restore previous default
+ }
- use IO::Socket; # this one is kinda a pipe?
- my $sock = IO::Socket::INET->new( 'www.example.com:80' );
+ # now should alternate . and +
+ while( 1 )
+ {
+ sleep 1;
+ print STDOUT ".";
+ print STDERR "+";
+ print STDOUT "\n" unless ++$count % 25;
+ }
+
+Besides the C<$|> special variable, you can use C<binmode> to give
+your filehandle a C<:unix> layer, which is unbuffered:
- $sock->autoflush();
+ binmode( STDOUT, ":unix" );
+
+ while( 1 ) {
+ sleep 1;
+ print ".";
+ print "\n" unless ++$count % 50;
+ }
+
+For more information on output layers, see the entries for C<binmode>
+and C<open> in L<perlfunc>, and the C<PerlIO> module documentation.
-You can also flush an C<IO::Handle> object without setting
-C<autoflush>. Call the C<flush> method to flush the buffer yourself:
+If you are using C<IO::Handle> or one of its subclasses, you can
+call the C<autoflush> method to change the settings of the
+filehandle:
use IO::Handle;
- open my( $printer ), ">", "/dev/printer");
- $printer->flush; # one time flush
+ open my( $io_fh ), ">", "output.txt";
+ $io_fh->autoflush(1);
+
+The C<IO::Handle> objects also have a C<flush> method. You can flush
+the buffer any time you want without auto-buffering
+ $io_fh->flush;
=head2 How do I change, delete, or insert a line in a file, or append to the beginning of a file?
X<file, editing>