Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

read/write subroutine

by epoptai (Curate)
on Jun 29, 2001 at 01:32 UTC ( [id://92476]=CUFP: print w/replies, xml ) Need Help??

Subroutine for reading and writing files from a single-user script when no file locking is required.
usage:

@array  = io('read',$file)
$string = io('read',$file)
io('write',$file,$string)
io('write',$file,\@array)
io('write',$file,$ref,'name') # Data::Dumper

Updated with grinder's improvements. Added the dump line.

sub io { # usage: # @array = io('read',$file) # $string = io('read',$file) # io('write',$file,$string) # io('write',$file,\@array) # io('write',$file,$ref,'name') my($bit,$file,$data) = @_; if($bit eq 'read'){ open IO,"< $file" or die "Cannot open $file for input: $!\n"; my@file = <IO>; close IO; wantarray ? return @file : return join '', @file; } if($bit eq 'write'){ open IO,"> $file" or die "Cannot open $file for output: $!\n"; print IO $data unless ref $data || $name; print IO @$data if ref $data eq 'ARRAY'; # print IO Data::Dumper->new([$data],[$name])->Indent(2)->Quotekeys( +0)->Dump if $name; close IO; } }

Replies are listed 'Best First'.
Re: read/write subroutine
by grinder (Bishop) on Jun 29, 2001 at 11:56 UTC

    epoptai, I'm starting to become familiar with your code! Have pored over xNN and reputer, I have a number of comments to make. The thing that has caused me the most grief working with you code is your die calls. Saying...

    open(IO,"< $file") or die "$!";

    ... is next to useless, you may was well omit the die, because the client has no idea what why things went amiss. Please, please, please, in future, use...

    open(IO,"< $file") or die "cannot open $file for input: $!\n";

    You owe it to yourself and your users to come up with more explicit error messages. When I had these cryptic messages appearing, the first thing I had to do was to edit the die call and then rerun the code to understand what was happening.

    Another issue I have with this is the use of mode parameters. One has to pass the routine a string containing 'read' or 'write'. Get that wrong that the routine mysteriously does nothing at all. What's more, there is absolutely no shared code between the read mode and the write mode, so I would say that you need two subroutines.

    In a similar vein, there is a second mode parameter that has to be 'array' or 'slurp'. I don't see the need for this. I see you expect arrays to be passed by reference, in which case that can be deduced by the ref operator. I would tend to just pass by value.

    You also seem to go through all sorts of contorsions to return a scalar or an array, when wantarray will do it for you.

    I hereby present the code that I used in my own hacked up copy of reputer. Note that I don't bother to check the return values from close. This is according to the belief that one can only check for the errors that you can do something about. I've never found a useful course of corrective action that a program can take if a close blows up. (Note that this is after many, many years in C and C++ of checking close return values and never having seen one fail). YMMV.

    use Carp qw/croak/; sub file_write { my $file = shift; open IO, ">$file" or croak "Cannot open $file for output: $!\n +"; print IO @_; close IO; } sub file_read { my $file = shift; open IO, $file or croak "Cannot open $file for input: $!\n"; my @data = <IO>; close IO; wantarray ? @data : join( '' => @data ); }

    I want to apologise in advance if this comes out sounding harsh. I find your PM applications simply amazing, but I find the code is exceptionally idiosyncratic and hard to comprehend. And I know I'm not alone. Someone asked about using cookies in the CB a few weeks ago and wanting to see some example code, so I told the person to take a look at reputer and the reply came back lightening fast "I can't read epoptai's code."


    --
    g r i n d e r
      I have actually seen close() fail in C. It occured with buffered output when the close() flushed the buffer and ran out of disk space.

      You are correct in that there was nothing that could be done in the program. However, I believe it is worth logging problems even when the program cannot correct them, so the person involved knows of the problem (a corrupt file in this case) and can take appropriate action.

      Returning an error code rather than a success code from the script can can also prevent subsequent programs from attempting to process the possibly incorrect output.

      No apology needed grinder. I appreciate the attention to detail and sound advice you provide. Your previous comments on reputer have caused a measurable improvement in my coding habits.

      My only excuse for not using ref or wantarray is not being familiar enough with them to have known to use them. The mode parameter did become more useful when extending the sub. I posted a simpler version of the one I use, which includes this write line. But $mode is now gone and this just checks for a 4th param:

      print IO Data::Dumper->new([$data],[$name])->Indent(2)->Quotekeys(0)-> +Dump if $name;
      By the way your wantarray line wouldn't work until I added returns:
      wantarray ? return @file : return join '', @file;
      Thanks again, I've updated the snippet with your improvements.
        You can simplify that wantarray call by adding a return in front and then letting the ternary operators do the rest like so:

        return wantarray ? @file : join '', @file;


        And here is my slightly changed version of your code.
        #!/usr/bin/perl sub io { # usage: # @array = io('read',$file) # $string = io('read',$file) # io('write',$file,\$string) # io('write',$file,\@array) my($bit,$file,$data) = @_; if($bit eq 'read'){ open IO,"< $file" or die "Cannot open $file for input: $!\n"; my @file = <IO>; close IO; return wantarray ? @file : join '', @file; } if($bit eq 'write'){ open IO,"> $file" or die "Cannot open $file for output: $!\n"; print IO ref $data eq 'ARRAY' ? @$data : ref $data eq "SCALAR"? $ +$data : ''; close IO; } } $string = "YO!"; io('write','file.txt',\$string);
        This way everything is passed as references and it deletes an extra line of code. :)

        $_.=($=+(6<<1));print(chr(my$a=$_));$^H=$_+$_;$_=$^H; print chr($_-39); # Easy but its ok.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: CUFP [id://92476]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others studying the Monastery: (3)
As of 2024-04-16 18:43 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found