diff options
Diffstat (limited to 'Master/tlpkg/tlperl/lib/pods/perlfaq5.pod')
-rw-r--r-- | Master/tlpkg/tlperl/lib/pods/perlfaq5.pod | 189 |
1 files changed, 121 insertions, 68 deletions
diff --git a/Master/tlpkg/tlperl/lib/pods/perlfaq5.pod b/Master/tlpkg/tlperl/lib/pods/perlfaq5.pod index bd969f4393f..76b6d3e0e2e 100644 --- a/Master/tlpkg/tlperl/lib/pods/perlfaq5.pod +++ b/Master/tlpkg/tlperl/lib/pods/perlfaq5.pod @@ -448,12 +448,12 @@ temporary files in one process, use a counter: my $base_name = sprintf "%s/%d-%d-0000", $temp_dir, $$, time; sub temp_file { - local *FH; + my $fh; my $count = 0; - until( defined(fileno(FH)) || $count++ > 100 ) { + until( defined(fileno($fh)) || $count++ > 100 ) { $base_name =~ s/-(\d+)$/"-" . (1 + $1)/e; # O_EXCL is required for security reasons. - sysopen my($fh), $base_name, O_WRONLY|O_EXCL|O_CREAT; + sysopen $fh, $base_name, O_WRONLY|O_EXCL|O_CREAT; } if( defined fileno($fh) ) { @@ -494,8 +494,8 @@ Berkeley-style ps: } We've used a hash slice in order to easily handle the fields of each row. -Storing the keys in an array means it's easy to operate on them as a -group or loop over them with for. It also avoids polluting the program +Storing the keys in an array makes it easy to operate on them as a +group or loop over them with C<for>. It also avoids polluting the program with global variables and using symbolic references. =head2 How can I make a filehandle local to a subroutine? How do I pass filehandles between subroutines? How do I make an array of filehandles? @@ -542,7 +542,7 @@ check out the Symbol or IO::Handle modules. =head2 How can I use a filehandle indirectly? X<filehandle, indirect> -An indirect filehandle is using something other than a symbol +An indirect filehandle is the use of something other than a symbol in a place that a filehandle is expected. Here are ways to get indirect filehandles: @@ -553,8 +553,7 @@ to get indirect filehandles: $fh = *SOME_FH{IO}; # blessed IO::Handle from *SOME_FH typeglob Or, you can use the C<new> method from one of the IO::* modules to -create an anonymous filehandle, store that in a scalar variable, -and use it as though it were a normal filehandle. +create an anonymous filehandle and store that in a scalar variable. use IO::Handle; # 5.004 or higher my $fh = IO::Handle->new(); @@ -644,7 +643,54 @@ techniques to make it possible for the intrepid hacker. =head2 How can I write() into a string? X<write, into a string> -See L<perlform/"Accessing Formatting Internals"> for an C<swrite()> function. +(contributed by brian d foy) + +If you want to C<write> into a string, you just have to <open> a +filehandle to a string, which Perl has been able to do since Perl 5.6: + + open FH, '>', \my $string; + write( FH ); + +Since you want to be a good programmer, you probably want to use a lexical +filehandle, even though formats are designed to work with bareword filehandles +since the default format names take the filehandle name. However, you can +control this with some Perl special per-filehandle variables: C<$^>, which +names the top-of-page format, and C<$~> which shows the line format. You have +to change the default filehandle to set these variables: + + open my($fh), '>', \my $string; + + { # set per-filehandle variables + my $old_fh = select( $fh ); + $~ = 'ANIMAL'; + $^ = 'ANIMAL_TOP'; + select( $old_fh ); + } + + format ANIMAL_TOP = + ID Type Name + . + + format ANIMAL = + @## @<<< @<<<<<<<<<<<<<< + $id, $type, $name + . + +Although write can work with lexical or package variables, whatever variables +you use have to scope in the format. That most likely means you'll want to +localize some package variables: + + { + local( $id, $type, $name ) = qw( 12 cat Buster ); + write( $fh ); + } + + print $string; + +There are also some tricks that you can play with C<formline> and the +accumulator variable C<$^A>, but you lose a lot of the value of formats +since C<formline> won't handle paging and so on. You end up reimplementing +formats when you use them. =head2 How can I open a filehandle to a string? X<string> X<open> X<IO::String> X<filehandle> @@ -727,64 +773,64 @@ Within Perl, you may use this directly: =head2 How come when I open a file read-write it wipes it out? X<clobber> X<read-write> X<clobbering> X<truncate> X<truncating> -Because you're using something like this, which truncates the file and +Because you're using something like this, which truncates the file I<then> gives you read-write access: open my $fh, '+>', '/path/name'; # WRONG (almost always) Whoops. You should instead use this, which will fail if the file -doesn't exist. +doesn't exist: open my $fh, '+<', '/path/name'; # open for update Using ">" always clobbers or creates. Using "<" never does either. The "+" doesn't change this. -Here are examples of many kinds of file opens. Those using sysopen() -all assume +Here are examples of many kinds of file opens. Those using C<sysopen> +all assume that you've pulled in the constants from C<Fcntl>: use Fcntl; To open file for reading: - open my $fh, '<', $path or die $!; - sysopen my $fh, $path, O_RDONLY or die $!; + open my $fh, '<', $path or die $!; + sysopen my $fh, $path, O_RDONLY or die $!; To open file for writing, create new file if needed or else truncate old file: - open my $fh, '>', $path or die $!; - sysopen my $fh, $path, O_WRONLY|O_TRUNC|O_CREAT or die $!; - sysopen my $fh, $path, O_WRONLY|O_TRUNC|O_CREAT, 0666 or die $!; + open my $fh, '>', $path or die $!; + sysopen my $fh, $path, O_WRONLY|O_TRUNC|O_CREAT or die $!; + sysopen my $fh, $path, O_WRONLY|O_TRUNC|O_CREAT, 0666 or die $!; To open file for writing, create new file, file must not exist: - sysopen my $fh, $path, O_WRONLY|O_EXCL|O_CREAT or die $!; - sysopen my $fh, $path, O_WRONLY|O_EXCL|O_CREAT, 0666 or die $!; + sysopen my $fh, $path, O_WRONLY|O_EXCL|O_CREAT or die $!; + sysopen my $fh, $path, O_WRONLY|O_EXCL|O_CREAT, 0666 or die $!; To open file for appending, create if necessary: - open my $fh, '>>' $path or die $!; - sysopen my $fh, $path, O_WRONLY|O_APPEND|O_CREAT or die $!; - sysopen my $fh, $path, O_WRONLY|O_APPEND|O_CREAT, 0666 or die $!; + open my $fh, '>>' $path or die $!; + sysopen my $fh, $path, O_WRONLY|O_APPEND|O_CREAT or die $!; + sysopen my $fh, $path, O_WRONLY|O_APPEND|O_CREAT, 0666 or die $!; To open file for appending, file must exist: - sysopen my $fh, $path, O_WRONLY|O_APPEND or die $!; + sysopen my $fh, $path, O_WRONLY|O_APPEND or die $!; To open file for update, file must exist: - open my $fh, '+<', $path or die $!; - sysopen my $fh, $path, O_RDWR or die $!; + open my $fh, '+<', $path or die $!; + sysopen my $fh, $path, O_RDWR or die $!; To open file for update, create file if necessary: - sysopen my $fh, $path, O_RDWR|O_CREAT or die $!; - sysopen my $fh, $path, O_RDWR|O_CREAT, 0666 or die $!; + sysopen my $fh, $path, O_RDWR|O_CREAT or die $!; + sysopen my $fh, $path, O_RDWR|O_CREAT, 0666 or die $!; To open file for update, file must not exist: - sysopen my $fh, $path, O_RDWR|O_EXCL|O_CREAT or die $!; - sysopen my $fh, $path, O_RDWR|O_EXCL|O_CREAT, 0666 or die $!; + sysopen my $fh, $path, O_RDWR|O_EXCL|O_CREAT or die $!; + sysopen my $fh, $path, O_RDWR|O_EXCL|O_CREAT, 0666 or die $!; To open a file without blocking, creating if necessary: @@ -796,7 +842,7 @@ be an atomic operation over NFS. That is, two processes might both successfully create or unlink the same file! Therefore O_EXCL isn't as exclusive as you might wish. -See also the new L<perlopentut>. +See also L<perlopentut>. =head2 Why do I sometimes get an "Argument list too long" when I use E<lt>*E<gt>? X<argument list too long> @@ -826,13 +872,13 @@ X<filename, special characters> (contributed by Brian McCauley) -The special two argument form of Perl's open() function ignores +The special two-argument form of Perl's open() function ignores trailing blanks in filenames and infers the mode from certain leading characters (or a trailing "|"). In older versions of Perl this was the only version of open() and so it is prevalent in old code and books. -Unless you have a particular reason to use the two argument form you -should use the three argument form of open() which does not treat any +Unless you have a particular reason to use the two-argument form you +should use the three-argument form of open() which does not treat any characters in the filename as special. open my $fh, "<", " file "; # filename is " file " @@ -951,7 +997,7 @@ X<append> X<file, append> If you are on a system that correctly implements C<flock> and you use the example appending code from "perldoc -f flock" everything will be OK even if the OS you are on doesn't implement append mode correctly -(if such a system exists.) So if you are happy to restrict yourself to +(if such a system exists). So if you are happy to restrict yourself to OSs that implement C<flock> (and that's not really much of a restriction) then that is what you should do. @@ -970,7 +1016,7 @@ C<syswrite> function which is simply a wrapper around your system's C<write(2)> system call. There is still a small theoretical chance that a signal will interrupt -the system level C<write()> operation before completion. There is also +the system-level C<write()> operation before completion. There is also a possibility that some STDIO implementations may call multiple system level C<write()>s even if the buffer was empty to start. There may be some systems where this probability is reduced to zero, and this is @@ -1072,26 +1118,6 @@ to each filehandle. =head2 How can I read in an entire file all at once? X<slurp> X<file, slurping> -Are you sure you want to read the entire file and store it in memory? -If you mmap the file, you can virtually load the entire file into a -string without actually storing it in memory: - - use File::Map qw(map_file); - - map_file my $string, $filename; - -Once mapped, you can treat C<$string> as you would any other string. -Since you don't actually load the data, mmap-ing is very fast and does -not increase your memory footprint. - -If you really want to load the entire file, you can use the -C<File::Slurp> module to do it in one step. - - use File::Slurp; - - my $all_of_it = read_file($filename); # entire file in scalar - my @all_lines = read_file($filename); # one line per element - The customary Perl approach for processing all the lines in a file is to do so one line at a time: @@ -1110,14 +1136,37 @@ you see someone do this: my @lines = <INPUT>; You should think long and hard about why you need everything loaded at -once. It's just not a scalable solution. You might also find it more -fun to use the standard Tie::File module, or the DB_File module's -$DB_RECNO bindings, which allow you to tie an array to a file so that -accessing an element the array actually accesses the corresponding +once. It's just not a scalable solution. + +If you "mmap" the file with the File::Map module from +CPAN, you can virtually load the entire file into a +string without actually storing it in memory: + + use File::Map qw(map_file); + + map_file my $string, $filename; + +Once mapped, you can treat C<$string> as you would any other string. +Since you don't necessarily have to load the data, mmap-ing can be +very fast and may not increase your memory footprint. + +You might also find it more +fun to use the standard C<Tie::File> module, or the C<DB_File> module's +C<$DB_RECNO> bindings, which allow you to tie an array to a file so that +accessing an element of the array actually accesses the corresponding line in the file. -You can read the entire filehandle contents into a scalar. +If you want to load the entire file, you can use the C<File::Slurp> +module to do it in one one simple and efficient step: + use File::Slurp; + + my $all_of_it = read_file($filename); # entire file in scalar + my @all_lines = read_file($filename); # one line per element + +Or you can read the entire file contents into a scalar like this: + + my $var; { local $/; open my $fh, '<', $file or die "can't open $file: $!"; @@ -1127,14 +1176,18 @@ You can read the entire filehandle contents into a scalar. That temporarily undefs your record separator, and will automatically close the file at block exit. If the file is already open, just use this: - $var = do { local $/; <$fh> }; + my $var = do { local $/; <$fh> }; + +You can also use a localized C<@ARGV> to eliminate the C<open>: + + my $var = do { local( @ARGV, $/ ) = $file; <> }; -For ordinary files you can also use the read function. +For ordinary files you can also use the C<read> function. read( $fh, $var, -s $fh ); -The third argument tests the byte size of the data on the INPUT filehandle -and reads that many bytes into the buffer $var. +That third argument tests the byte size of the data on the C<$fh> filehandle +and reads that many bytes into the buffer C<$var>. =head2 How can I read in a file by paragraphs? X<file, reading by paragraphs> @@ -1228,7 +1281,7 @@ not POSIX, not Unix, etc.) systems. You should also check out the Frequently Asked Questions list in comp.unix.* for things like this: the answer is essentially the same. -It's very system dependent. Here's one solution that works on BSD +It's very system-dependent. Here's one solution that works on BSD systems: sub key_ready { @@ -1267,7 +1320,7 @@ Or write a small C program using the editor of champions: % ./fionread 0x4004667f -And then hard code it, leaving porting as an exercise to your successor. +And then hard-code it, leaving porting as an exercise to your successor. $FIONREAD = 0x4004667f; # XXX: opsys dependent @@ -1320,7 +1373,7 @@ Or even with a literal numeric descriptor: my $fd = $ENV{MHCONTEXTFD}; open $mhcontext, "<&=$fd"; # like fdopen(3S) -Note that "<&STDIN" makes a copy, but "<&=STDIN" make +Note that "<&STDIN" makes a copy, but "<&=STDIN" makes an alias. That means if you close an aliased handle, all aliases become inaccessible. This is not true with a copied one. |