Solved

Copying binary files

Posted on 1998-10-15
7
207 Views
Last Modified: 2010-03-05
I am writing a Perl program that runs on NT. I have NFS mounted unix filesystems. I will need to copy binary files from the NT system to the Unux filesystem. I have written a subroutines that accepts two parameters, the full source path including filename, and the destination path. I suspect that I would be opening a filehandle to the destination file and opening another to the source. I guess that I would then simply print one to the other, but I think I need binary mode somewhere.

I hope this is clear enough.
Thanx
Angel
0
Comment
Question by:aleyva
  • 3
  • 2
  • 2
7 Comments
 
LVL 5

Accepted Solution

by:
b2pi earned 200 total points
ID: 1205351
perldoc -f binmode

will tell you what you might be looking for.  However, since you have
file systems nfs mounted, why not just do

system('copy /b src_file_on_nfs_fs dst_file_on_local_storage');

unless you're doing this from the UNIX side, in which case it would be

system('cp src_file_on_remote_NT_storage dst_file_on_unix_fs ');

you might also want to check out using Net::FTP, but you may not have
servers set up.

If you're convinced you want to do it by hand, try (Note that this is
off the top of my head, some clean up may be necessary, your mileage
may vary, offer not valid in the state of Utah)

sub MyCP ( $$ );

sub MyCP ( $$ ) {

    my($src, $dst) = @_;

    my($error) = 0;
    if (!-f "$src") {
       carp "MyCP: Invalid src file '$src'";
       $error ++;
    }
    if (!-f "$dst") {
       carp "MyCP: Invalid dst file '$dst'";
       $error ++;
    }
    return undef if $error;

    open(SRC, "<$src") || $error++;
    if ($error) {
       carp "Unable to open src file '$src' : $!";
       return undef;
    }
    open(DST, ">$dst") || $error++;
    if ($error) {
       carp "Unable to open dst file '$dst' : $!";
       close(SRC);
       return undef;
    }
    binmode SRC;
    binmode DST;

    my($count) = 64*1024;
    my($bcount, $rcount, $wcount, $buffer, $rcount);

    for ($bcount = -s $src; $bcount; $bcount -= $wcount) {
          $rcount = sysread(SRC, $buffer, $count);
      $wcount = undef;
      if (!defined($rcount)) {
         carp "src read failed: $!";
      } else {
          $wcount = syswrite(DST, $buffer, $rcount);
          if (!defined($wcount) || $wcount != $rcount) {
             carp "dst write failed: $!";
          }
      }
      if (!defined($wcount) || $wcount != $rcount) {
          close(SRC);
          close(DST);
          return undef;
        }
    }
    close(SRC);
    close(DST);
    return 1;
}

0
 

Author Comment

by:aleyva
ID: 1205352
b2pi, Why don't you have any real profile data? Anyway,

I have a couple of questions/comments.
First of all, what is the carp () command doing?

Next, I have done the following and it works, so I would simply want to ask why it is or isn't a good idea to do it this way.

      open (SRC,"$source");
      open (DEST,">$destination");
      binmode (SRC);
      binmode (DEST);
      print DEST <SRC>;
      close (SRC);
      close (DEST);

Again, this works because I am able to read the files on the UNIX end.

I tried the system ("copy /b $source $destination"); command, but the files never appeared, this is why I am now trying with perl. Not only that, it makes it more portable.

One more, would it be asking too much to have you comment the code? (You must be rolling your eyes by now with that one).

Appreciated
Angel

PS    I increased the points.
0
 
LVL 5

Expert Comment

by:b2pi
ID: 1205353
1.) Why do I need profile data?
2.) carp issues warnings with a bit of trace info.  I note that I
forgot that at the top of the code there has to be a


use Carp;

line.  Take a look at

perldoc Carp

for more information. (Note that, as with warn, you can defined a
$SIG__WARN__} handler to suppress messages)

3.) There's probably no problem with your code, save for two
bugaboos. First, no error handling, and no way to determine if the
copy worked (or, if it didn't, where, and why not).  Secondly, it will
read the entire file into memory as one chunk.  That could be a bit of
a problem if memory resources are .... constrained.  Suppose you have
a 64M machine, and a 128M file.  Even with virtual memory, you're
going to be waiting a long, long time.

4.) Comment?  It's kind of small, but...

use strict;
use Carp;

## Prototype to put at the top of code
sub MyCP ( $$ );


## Intervening code..., including that which calls MyCP
## like
##
##    die "MyCP failure" if !MyCP($src, $dst)
##

sub MyCP ( $$ ) {
    my($src, $dst) = @_;
    my($error) = 0;
    ## Ensure that the source file exists
    if (!-f "$src") {
        carp "MyCP: Invalid src file '$src'";
        $error ++;
    }
    ## Ensure that the destination file exists
    if (!-f "$dst") {
        carp "MyCP: Invalid dst file '$dst'";
        $error ++;
    }
    return undef if $error;
    ## Open the source file
    open(SRC, "<$src") || $error++;
    if ($error) {
        carp "Unable to open src file '$src' : $!";
        return undef;
    }
    ## Open the destination file
    open(DST, ">$dst") || $error++;
    if ($error) {
        carp "Unable to open dst file '$dst' : $!";
        close(SRC);
        return undef;
    }
    ## Set both source and destination files to binmode
    binmode SRC;
    binmode DST;
    ## Define a constant for maximum read size
    my($count) = 64*1024;
    ## declare some variables (byte count, read count, write count,
    ## a buffer for reads and writes, and bytes remaining)
    my($bcount, $rcount, $wcount, $buffer, $rcount);
    ## Note that -s $src returns the size of the file $src
    for ($bcount = -s $src; $bcount; $bcount -= $wcount) {
      ## Read the data, $rcount is the number of bytes read
        $rcount = sysread(SRC, $buffer, $count);
        $wcount = undef;
      ## Complain on error
        if (!defined($rcount)) {
            carp "src read failed: $!";
        } else {
          ## Write the data, $wcount is the number of bytes written
            $wcount = syswrite(DST, $buffer, $rcount);
          ## Complain on error
            if (!defined($wcount) || $wcount != $rcount) {
                carp "dst write failed: $!";
            }
        }
      ## Complain and return on error
        if (!defined($wcount) || $wcount != $rcount) {
            close(SRC);
            close(DST);
            return undef;
        }
    }
    ## clean up
    close(SRC);
    close(DST);
    # Done
    return 1;
}

0
Does Powershell have you tied up in knots?

Managing Active Directory does not always have to be complicated.  If you are spending more time trying instead of doing, then it's time to look at something else. For nearly 20 years, AD admins around the world have used one tool for day-to-day AD management: Hyena. Discover why

 
LVL 84

Expert Comment

by:ozo
ID: 1205354
b2pi, if you're not going to handle partial writes from the sysewrite, it may be safer to use print, which handles all that for you.
0
 

Author Comment

by:aleyva
ID: 1205355
b2pi,

The reason for the profile, is primarily to know your background/experience, and a name, but no big deal.

I implemented your solution, and it works like a champ almost. I don't think that it is your code as much as it might be the file, but I have a postscript file that was saved on a MAC as BINARY Postscript. The programs loops forever trying to write the file even though it is returning 0 values for rcount and wcount. I simply put an check if these values are 0, then exit.

Thanx again,
Angel
0
 
LVL 5

Expert Comment

by:b2pi
ID: 1205356
ozo, I thought I was handling partial results from the write ($wcount
!= $rcount). It is true that I could retry the write, but, really,
I don't think I've ever had a need.

I find it curious that a sysread could return 0 bytes on a proper call...
0
 
LVL 84

Expert Comment

by:ozo
ID: 1205357
You may not have ever had a signal sent to you during a syswrite
(write is different, don't try to mix write and syswrite calls on the same filehandle)
But that doesn't mean you will never have the need.
0

Featured Post

Best Practices: Disaster Recovery Testing

Besides backup, any IT division should have a disaster recovery plan. You will find a few tips below relating to the development of such a plan and to what issues one should pay special attention in the course of backup planning.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

On Microsoft Windows, if  when you click or type the name of a .pl file, you get an error "is not recognized as an internal or external command, operable program or batch file", then this means you do not have the .pl file extension associated with …
Checking the Alert Log in AWS RDS Oracle can be a pain through their user interface.  I made a script to download the Alert Log, look for errors, and email me the trace files.  In this article I'll describe what I did and share my script.
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…

831 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question