Irishboy24 has asked for the wisdom of the Perl Monks concerning the following question:

Hey Monks,
I am having trouble with a script of mine. need your help. i create a package called Packagetest.pl. it has a subroutine called ReadFile() which has to read a txt file, then sort it and print it out. Now i have many txt files which are in the same format, so i wanted to make it generic by passing the filename as an argument to the subroutine. this is when the error happened.
The error reads as follows:
Error:cannot read the file: No such file or directory at Packagetest.pl line 14.

Here is the code in Packagetest.pl
package Packagetest; BEGIN{ print"You are using Packagetest\n"; } sub ReadFile { $file = @_; open(DATA,"$file") || die "cannot read the file: $!"; while (<DATA>) { chomp; @tokens = split /\|/; print "Wrestlername: $tokens[0]\n"; print "Crowdreaction: $tokens[1]\n"; print "Specialmove: $tokens[2]\n\n"; } } return 1; END{ print"Thank you for using the package\n"; }
Here is the code for the file that calls this package.
#!/usr/bin/perl -w require 'Packagetest.pl'; Packagetest::ReadFile("datafile");

Note that both the datafile is a txt file that has to be read.
The package,txtfile and the script that calls the package are in the same dir

Thanks
Irishboy

Replies are listed 'Best First'.
Re: Perl Packages Issue in a script.
by ikegami (Patriarch) on Oct 01, 2009 at 22:09 UTC

    Trying to put an array into a scalar doesn't make much sense. It was deemed that when you attempt to evaluate an array as a scalar, you get its length.

    Other issues:

    • $file is a global variable. Use my!
    • @tokens is a global variable. Use my!
    • DATA is a global variable. Use my!
    • You're hiding errors (including the previous three) by not using use strict; use warnings;.
    • Since DATA is a global variable and you never explicitly close the file handle, the file handle is left open much longer than it needs to be.
    • DATA is the name of special file handle. Let's not use that.
    • What is a sub that reads a file doing printing?
    • Modules are given the .pm extension.
    • Why are you interpolating $file into a string (i.e. "$file") instead of just passing $file to open?
    • Using open's 3-arg open is safer and less problematic.
    • There's no reason to include the line number of the error in IO error message.
    # Packagetest.pm package Packagetest; sub ReadFile { my ($fn) = @_; open(my $fh, '<', $fn) or die("Can't open file \"$fn\": $!\n"); my @recs; while (<$fh>) { chomp; my @tokens = split /\|/; push @recs, \@tokens; } return \@recs; } 1;
    #!/usr/bin/perl -w use strict; use warnings; use Packagetest; my $recs = Packagetest::ReadFile("datafile"); for my $rec (@$recs) { print "Wrestlername: $recs->[0]\n"; print "Crowdreaction: $recs->[1]\n"; print "Specialmove: $recs->[2]\n"; print "\n"; }
      Hi. Some of the things you pointed out are very relevant and hence i've modified the script now. Note that this is not a module , its a package. I would like to keep the dimension of my script the way it is.
      Packagtest.pl
      package Packagetest; BEGIN{ print"You are using Packagetest\n"; } sub ReadFile { use strict; use warnings; my ($fn) = @_; open(my $fh, '<', $fn) || die "cannot read the file: $!"; while (<$fh>) { chomp; my @tokens = split /\|/; print "Wrestlername: $tokens[0]\n"; print "Crowdreaction: $tokens[1]\n"; print "Specialmove: $tokens[2]\n\n"; } } return 1; END{ print"Thank you for using the package\n"; }
      Here is the script that calls this package
      TestPackage.pl
      #!/usr/bin/perl -w use strict; use warnings; require 'Packagetest.pl'; Packagetest::ReadFile("datafile");

        What do you mean by package? There are scripts, modules and distributions. You used require, so it better be a module. If it's not a module, it doesn't make sense to use require or use. It's a bug.

        Why did you revert the extension change? It confuses your readers and maintainers. It also forces you to use require instead of use. Not only is that really unusual, it serves no benefit and it causes a number of issues.

        Why did you remove the file name from the message? It would have solved your original problem if the error message had included the file name. It helps elsewhere too.

        Why did you add the line number to the IO message (by removing the "\n"). If your program can't open the file because it wasn't found or because of a permission problem or for any other reason, the person reading the message has no need to know the error occurred at line 11 of your module to fix the problem.

        Why did you move use strict; and use warnings; into the sub, effectively turning them off for the rest of the module.

        Why did you move the output back into the reader? That makes no sense.

Re: Perl Packages Issue in a script.
by Bloodnok (Vicar) on Oct 01, 2009 at 22:32 UTC
    Just in case you missed it, hidden away in ikegamis post is ...Modules are given the .pm extension... - which means that if a package is to be used or required, then it has to reside in a .pm file e.g. in your case, rename Packagetest.pl to Packagetest.pm.

    A user level that continues to overstate my experience :-))
Re: Perl Packages Issue in a script.
by rovf (Priest) on Oct 02, 2009 at 07:05 UTC
    open(DATA,"$file") || die "cannot read the file: $!";
    I think if you change this to

    open(DATA,"$file") || die "cannot read $file: $!";
    you can narrow down the problem considerably ;-) And for the safe side, I suggest you are using open(DATAFH,'<',$file), since DATA is a "reserved filehandle" in Perl (like STDIN or STDERR), and the 3-argument open is safer anyway, if the file to be opened is stored in a variable.

    -- 
    Ronald Fischer <ynnor@mm.st>
Re: Perl Packages Issue in a script.
by jakobi (Pilgrim) on Oct 01, 2009 at 22:46 UTC

    just eyeing one not yet mentioned detail very sceptically and late at night:

    Is it just me or is $file in the stated sub ReadFile indeed identical to 1, assuming ReadFile itself was called correctly with one argument... ?

    Fix with e.g. my ($file)=@_

    (if you followed ikegami's pointers, you should have touched&fixed that one already, right?).

    Good - you've seen & done it already, I should have reloaded the thread before creating the node :).