Re: Usage of File Handles
by poj (Abbot) on Feb 07, 2019 at 21:36 UTC
|
#open OUTPUT, '>', 'three_Freds.out':
open OUTPUT, '>', 'three_Freds.out';
# correction here ^
| [reply] [d/l] |
Re: Usage of File Handles
by Your Mother (Archbishop) on Feb 07, 2019 at 21:31 UTC
|
| [reply] [d/l] |
Re: Usage of File Handles
by Corion (Patriarch) on Feb 07, 2019 at 21:28 UTC
|
Please edit your post and show us the exact error messages you get.
Also, consider the answers you got in Explicit Package?. Most likely they apply here as well.
| [reply] |
Re: Usage of File Handles
by haukex (Archbishop) on Feb 08, 2019 at 06:33 UTC
|
open CONFIG, '<', 'three_Freds';
In addition to what the others have pointed out, I would very strongly recommend you use the more modern form of open with lexical file handles instead of global handles, and that you check the return value of the function for errors. That would look something like the following. By the way, what is the point of the $three_Freds variable if you're not using it? Also, note that s/\n/Wilma/g; won't do anything since you're removing the newline on each line with chomp.
#!/usr/bin/env perl
use warnings;
use 5.012;
my $in_filename = 'three_Freds';
my $out_filename = 'three_Freds.out';
open my $config_fh, '<', $in_filename or die "$in_filename: $!";
open my $output_fh, '>', $out_filename or die "$out_filename: $!";
my $three_Freds = $ARGV[0];
if (! defined $three_Freds) {
die "Usage: $0 filename";
}
while (<$config_fh>) {
chomp;
s/fred/\n/gi;
s/Wilma/Fred/gi;
s/\n/Wilma/g;
print $output_fh $_;
}
| [reply] [d/l] [select] |
Re: Usage of File Handles
by kcott (Archbishop) on Feb 08, 2019 at 13:37 UTC
|
G'day catfish1116,
Here's some additional information that I didn't see in any of the responses.
You're getting errors reported because you're implicitly using the strict pragma.
It's good that you're doing this but perhaps you were unaware of this implicit usage.
It occurs because you've specified that version 5.12, or later, is required.
See use for details.
When specifying a version, the 5.012 form is preferred over the v5.12 form for backwards compatibility.
It is, after all, older versions of Perl that you want to target with such a statement.
That's also described in more detail in use.
I concur with advice you've received about using lexical filehandles with the 3-argument form
of open.
Hand-crafting '... or die "...";' messages is error-prone:
you can forget to add them;
you can forget to update them when related code changes;
you can omit important information such as that contained in $!.
To avoid these problems, and save yourself a lot of typing,
consider using the autodie pragma.
I saw that CONFIG vs. $CONFIG was pointed out;
you have the same problem with OUTPUT vs. $OUTPUT.
| [reply] [d/l] [select] |
Re: Usage of File Handles
by harangzsolt33 (Deacon) on Feb 07, 2019 at 21:46 UTC
|
Yeah, you can either use a positive integer as a file handle, or you can use a text label or you may use a variable name with a dollar sign in front of it, but if you do that, then you have to declare the variable my $INPUT_FILE_HANDLE; before you can use it. Notice, I like to write the < > signs and the file name as one string. That way my Perl script will be backward compatible with older DOS Perl. (I currently use TinyPerl 5.8, but it's neat when I can run the same script in DOS as well.) Also, don't forget to close your opened file handles before the program ends. ;)
#!/usr/bin/perl -w
use strict;
use warnings;
open(INPUT_FILE_HANDLE, '< c:/boot.ini') or die('Cant open file for re
+ading');
open(OUTPUT_FILE_HANDLE, '> c:/outfile.txt') or die('Cant open file fo
+r writing');
print <INPUT_FILE_HANDLE>;
print OUTPUT_FILE_HANDLE "Hello world!!!\n";
close OUTPUT_FILE_HANDLE;
close INPUT_FILE_HANDLE;
| [reply] [d/l] |
|
|
Yeah, you can either use a positive integer as a file handle, or you can use a text label
Note that catfish1116 is using Perl 5.12 or better, in which case lexical filehandles are generally recommended. Also, to pick a nit, it's not a "text label", it's actually a "bareword filehandle", which is essentially a global variable, which is one of the reasons that such filehandles are usually not recommended anymore.
don't forget to close your opened file handles before the program ends
Although closing filehandles explicitly as soon as possible is a good idea, the way you've written this implies that Perl doesn't close filehandles automatically, but it does. Another advantage of lexical filehandles is that they are closed automatically as soon as they go out of scope.
Note that most of this has been discussed before. Lexical filehandles were introduced in Perl 5.6, so they are available even in your TinyPerl 5.6 and 5.8.
| [reply] |
Re: Usage of File Handles
by harangzsolt33 (Deacon) on Feb 07, 2019 at 22:13 UTC
|
What do you think about this? I like to enclose my file I/O functions in subs, so I don't even have to deal with opening files and stuff like that. Call me lazy. LOL
#!/usr/bin/perl -w
use strict;
use warnings;
########################################
my $INPUT_FILE_NAME;
my $OUTPUT_FILE_NAME;
Init();
my @LINES = ReadTextFile($INPUT_FILE_NAME);
# DO SOMETHING
CreateFile($OUTPUT_FILE_NAME, join("\n", @LINES))
or die("Can't write to file...\n\n");
print "SUCCESS!\n\n";
exit;
########################################
sub Init
{
my $SELF = GetFileName($0);
$INPUT_FILE_NAME = (@ARGV) ? $ARGV[0] : '';
$INPUT_FILE_NAME or die("\nUsage: $SELF <filename>\n\n");
$OUTPUT_FILE_NAME = $INPUT_FILE_NAME . '.out';
}
# Usage: STRING = Trim(STRING) - Removes whitespace, newline character
+s and other special characters before and after STRING. Returns a new
+ string.
sub Trim { @_ or return ''; my $T = $_[0]; defined $T or return ''; my
+ $N = length($T); my $X = 0; my $Y = 0; while ($N--) { if (vec($T, $N
+, 8) > 32) { $X = $N; $Y or $Y = $N + 1; } } return substr($T, $X, $Y
+ - $X); }
# Usage: FILE_NAME_ONLY = GetFileName(FULL_NAME) - Returns only the na
+me portion of a full file name.
sub GetFileName { @_ or return ''; my $W = shift; defined $W or return
+ ''; length($W) or return ''; $W =~ tr|\\|/|; return substr($W, rinde
+x($W, '/') + 1, length($W)); }
# Usage: STRING = _FileName(\@_) - Removes the first argument from @_
+just like shift() does and returns a file name. This function does no
+t check syntax, but it does remove some illegal characters (<>|*?) fr
+om the name that obviously should not occur in a file name. If the fi
+le name doesn't contain any valid characters, then returns an empty s
+tring.
sub _FileName { @_ or return ''; my $N = shift; $N = shift(@$N); defin
+ed $N or return ''; length($N) or return ''; my $c; my $j = 0; my $V
+= 0; for (my $i = 0; $i < length($N); $i++) { $c = vec($N, $i, 8); ne
+xt if ($c == 63 || $c == 42 || $c < 32); last if ($c == 60 || $c == 6
+2 || $c == 124); if ($c > 32) { $V = $j + 1; } if ($V) { $i == $j or
+vec($N, $j, 8) = $c; $j++; } } return substr($N, 0, $V); }
# Usage: ARRAY = ReadTextFile(FILE_NAME, [LIMIT]) - Reads the contents
+ of a text file and returns the lines in an array. If a second argume
+nt is provided, then only the first few lines will be processed. Each
+ line is trimmed before it is stored.
sub ReadTextFile { my @A; my $F = _FileName(\@_); length($F) or return
+ @A; my $M = @_ ? shift : 99999999; defined $M or return @A; $M or re
+turn @A; -f $F or return @A; -s $F or return @A; my $H; my $B; my $i
+= 0; open $H, "<$F" or return @A; while (my $L = <$H>) { $A[$i++] = T
+rim($L); $i < $M or last; } close $H; return @A; }
# Usage: STATUS = CreateFile(FILE_NAME, STRING) - Creates and overwrit
+es a file. Returns 1 on success or 0 if something went wrong.
sub CreateFile { my $F = _FileName(\@_); length($F) or return 0; my $S
+ = (@_) ? shift : ''; return 0 unless defined $S; open(my $H, ">$F")
+or return 0; if (length($S)) { print $H $S or return 0; } close $H or
+ return 0; return 1; }
| [reply] [d/l] |
|
|
What do you think about this?
You're of course free to write your code in any style you like, but I do have to say it's not something I would recommend for a beginner.
it does remove some illegal characters (<>|*?) from the name that obviously should not occur in a file name
Those are all perfectly valid characters in many *NIX OSes, see e.g. this. I also don't understand why some of those characters are simply removed and others cause the string to be cut off at that point.
my $M = @_ ? shift : 99999999;
This causes a somewhat arbitrary silent cutoff at this many lines. In general, in that code there are lots of errors that are silently swallowed.
In general, your use of vec for string operations is not a good idea for Unicode strings (in fact, it will become a fatal error in Perl 5.32). If you need to treat a string as a sequence of characters, you could either split //, $str or use substr, although normally regular expressions can handle many of the cases where one would need to do so in other languages.
Plus, there are lots of other stylistic choices that I would not recommend to a newcomer: Reinvented wheels (GetFileName instead of File::Basename or File::Spec, GetFileName($0) instead of $FindBin::Script, Trim instead of e.g. s/^[\0-\x20]+|[\0-\x20]+$//g), two-argument instead of three-argument open, uppercase variable names for non-constant variables, obfuscation by using single-letter variable names and packing function bodies on one line, unused variables...
Sorry for the long critique, but as I said this is in the context of giving code to an apparent beginner.
| [reply] [d/l] [select] |
|
|
it does remove some illegal characters (<>|*?) from the name that obviously should not occur in a file name
Those are all perfectly valid characters in many *NIX OSes, see e.g. this. I also don't understand why some of those characters are simply removed and others cause the string to be cut off at that point.
Okay, I was told earlier that when we open a file such as open FILEHANDLE, "< $FILE_NAME" then it's a good idea to make sure that $FILE_NAME does not contain any special characters such as | > < because it's a potential vulnerability, especially if you get your file name from some other place like arguments. Your script could be hacked, and it may end up doing something you didn't want.. That's why I check the file name.
Also, there is no point in doing this : open FILEHANDLE, "< *.*" so again those special characters should not appear in that space. It's perfectly okay to include them when you do a search, but not when you're trying to open a file for reading.
| [reply] |
|
|
|
|
|
|
Call me lazy.
It appears that your personal flavor of laziness requires quite a lot of work.
| [reply] |
|
|
| [reply] |
Re: Usage of File Handles
by catfish1116 (Beadle) on Feb 08, 2019 at 20:32 UTC
|
Variable "$CONFIG" is not imported at ./Chapter9_Exer3 line 15.
Variable "$OUTPUT" is not imported at ./Chapter9_Exer3 line 20.
syntax error at ./Chapter9_Exer3 line 8, near "'three_Freds.out':"
Can't use global $0 in "my" at ./Chapter9_Exer3 line 12, near "Usage:
+$0"
Global symbol "$CONFIG" requires explicit package name at ./Chapter9_E
+xer3 line 15.
Global symbol "$OUTPUT" requires explicit package name at ./Chapter9_E
+xer3 line 20.
Execution of ./Chapter9_Exer3 aborted due to compilation errors.
| [reply] [d/l] |
|
|
You already got suggestions on how to fix these errors:
Variable "$CONFIG" is not imported at ./Chapter9_Exer3 line 15.
Variable "$OUTPUT" is not imported at ./Chapter9_Exer3 line 20.
Global symbol "$CONFIG" requires explicit package name at ./Chapter9_E
+xer3 line 15.
Global symbol "$OUTPUT" requires explicit package name at ./Chapter9_E
+xer3 line 20.
You open the filehandles CONFIG and OUTPUT, and then try to use the variables $CONFIG and $OUTPUT, these are two different things. You need to either change your open calls to use lexical variables, like I showed here, or remove the $ sigil, as pointed out by Your Mother and kcott.
syntax error at ./Chapter9_Exer3 line 8, near "'three_Freds.out':"
Can't use global $0 in "my" at ./Chapter9_Exer3 line 12, near "Usage:
+$0"
The first error was pointed out by poj: You have a typo in that line. The second error is just being caused by the parser getting confused after seeing the first error.
| [reply] [d/l] [select] |