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

I am a newbie to Perl. This is a total new world for me so if my terminology is incorrect please forgive me. I am writing some FTP Perl scripts. What I am trying to figure out is how I can get the FTP output logs. I am used to doing FTP on the AS400 which will allow me to redirect the output logs to a file so I can get the bytes transferred. Now I am working with HP UNIX with Perl scripts. I do have a script working with Net::FTP. With Net::FTP I see I could do size but that is the size on the remote system. So my question is can I get the bytes transferred either via a method from the Net::FTP or from a log.

Replies are listed 'Best First'.
Re: FTP logs
by erasei (Pilgrim) on Nov 06, 2002 at 14:39 UTC
    As you state, the only file size method in Net::FTP (the size function) tells you the file size on the remote system. File sizes can be different on different platforms.

    My only idea of how to get an accurate file size locally would be to stat the file once it's been transferred. Something like:

    my $file_size = (stat($filename))[7];
    should give you what you want to know, if in a round-about sort of way. If you have more than one file, just use your favorite loop. As with all things Perl, TIMTOWTDI, and I am sure there are some guru's around with more clever ways.
Re: FTP logs
by Aristotle (Chancellor) on Nov 06, 2002 at 15:00 UTC

    For one, you can pass a Debug => 1 to new() - debug messages will then be written to STDERR, which you can capture in whichever fashion your shell provides.

    For another, if you transfer files using the get() method, then you can store this method's return value which will be the filename the requested file got stored as locally, and then stat this file, as per erasei's suggestion.

    And finally, if you use the retr() method and do the transfer logistics manually, you can call bytes_read() on the Net::FTP::dataconn object it returns at any point to query the amount of data transferred so far.

    All of this is mentioned in the Net::FTP POD page.

    Makeshifts last the longest.

Re: FTP logs
by jdporter (Paladin) on Nov 06, 2002 at 17:07 UTC
    It is apparent that the author of Net::FTP did not consider that a user might want to do what you're trying to do. However, it is not impossible. What follows is a solution which uses subclassing. If you need help with this, let me know. But it should be fairly straightforward to customize for your needs.
    use Net::FTP; # subclass Net::FTP, as well as Net::FTP::A which is # the class of the data connection object. { package My::Net::FTP::A; use base qw( Net::FTP::A ); # override the "read" method: sub read { my $self = shift; my $r = $self->SUPER::read( @_ ); ## ## This is where you can put your custom code. ## E.g. just print out the running total: ## print STDERR "read ", $self->bytes_read, " bytes so far.\n"; ## $r } package My::Net::FTP; use base qw( Net::FTP ); # override the "retr" method: sub retr { my $self = shift; bless $self->SUPER::retr( @_ ), 'My::Net::FTP::A' } } # when you make your Net::FTP object, make it from # your own subclass instead (in this case, My::Net::FTP) - my $ftp = My::Net::FTP->new( "ftp.archive.net", BlockSize => 512, # very useful parameter! ); # and use it: $ftp->login( 'user', 'passwd' ); $ftp->get( $file ); $ftp->quit;
      I kind of understand some of what you are doing. I do not understand the bless. Also does the SUPER mean use the highest class?
        "bless" causes the object to be of a certain class.

        In this case, we are given an object which happens to be of class "Net::FTP::A", and we force it to be of class "My::Net::FTP::A". Since "My::Net::FTP::A" is a subclass of "Net::FTP::A", everything will still work. We simply override the little bit that we want to be different. In our overriding version, we do a little bit... then we chain through to the original version. Since the original version is owned by the parent class (or "super-class"), we use the special form  $obj->SUPER::method() to call it.

        UPDATED
        "SUPER" means look up the given method, skipping the definition in the current class. In this case, the method is found in the immediate parent, even though SUPER could, if necessary, search all the way back to UNIVERSAL.

        Does that clarify it at all?