# Net::FTP questions

**URL:** <https://www.ruby-forum.com/t/net-ftp-questions/68354>\
**Category:** Ruby\
**Created:** [September 12, 2006, 12:39am UTC](https://www.ruby-forum.com/t/net-ftp-questions/68354 "2006-09-12T00:39:22Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Lincoln\_Anderson](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/e79b87/32.png) [@Lincoln\_Anderson](https://www.ruby-forum.com/u/Lincoln_Anderson)\
**Post date:** [September 12, 2006, 12:39am UTC](https://www.ruby-forum.com/t/net-ftp-questions/68354/1 "2006-09-12T00:39:22Z")

</div>

-----BEGIN PGP SIGNED MESSAGE-----  
Hash: SHA1

Hello…

I am attempting to write a client side script that mirrors a user’s  
/home/\* on a remote server. Granted, I _could_ use ftpmirror in my  
Ubuntu distribution, but I’d like to get more familiar with network  
and filesystem operations in Ruby.

The basic algorithm as I see it would be to logon, get a list of all  
files and folders via the Net::FTP.list(\*args) command, run it through  
a block or a for loop or some other iterator, ducking into  
subdirectories as needed (and mkdir-ing them on the client side), and  
doing a get() of all the files in each subdirectory.

Here’s where my problem comes in. How can I tell from the list array  
whether an item is a directory or a file to be copied? Is there  
something I can use (such as an FTP command) to catch a clue on how to  
implement this? I know this is possible, as ftpmirror is done with  
PERL and Ruby can do anything PERL can do - better 🙂

Google is no help, and neither is running searches on ruby-talk  
itself… Anyone done anything similar and have any tips? Any advice  
whatsoever is appreciated.

Lincoln Anderson  
-----BEGIN PGP SIGNATURE-----  
Version: GnuPG v1.4.2 (MingW32)  
Comment: Using GnuPG with Mozilla - [http://enigmail.mozdev.org](http://enigmail.mozdev.org)

iD8DBQFFBeV4Kte2c0P8BH0RAo4TAJ9sdFbwO/W6JdMpIxNULjC0ivjGdACbBSr5  
Qqg1SW+aKBPyWB4rURKu5Lk=  
=2OL8  
-----END PGP SIGNATURE-----

---

<div class="post-metadata">

**Author:** ![Lincoln\_Anderson](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/e79b87/32.png) [@Lincoln\_Anderson](https://www.ruby-forum.com/u/Lincoln_Anderson)\
**Post date:** [September 12, 2006, 10:46am UTC](https://www.ruby-forum.com/t/net-ftp-questions/68354/2 "2006-09-12T10:46:26Z")

</div>

Hi,

Le mardi 12 septembre 2006 Ã 07:39 +0900, Lincoln Anderson a Ã©crit :

> Here’s where my problem comes in. How can I tell from the list array  
> whether an item is a directory or a file to be copied? Is there  
> something I can use (such as an FTP command) to catch a clue on how to  
> implement this? I know this is possible, as ftpmirror is done with  
> PERL and Ruby can do anything PERL can do - better 🙂

The output of FTP#ls should be something like :  
drwxr-x— 2 login ftp 96 Sep 11 16:07 mydir  
-rwxr-x— 2 login ftp 96 Sep 11 16:07 myfile

So you will know an entry is a directory if the string begins by “d”.

Vincent

---

<div class="post-metadata">

**Author:** ![Lincoln\_Anderson](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/e79b87/32.png) [@Lincoln\_Anderson](https://www.ruby-forum.com/u/Lincoln_Anderson)\
**Post date:** [September 12, 2006, 4:51pm UTC](https://www.ruby-forum.com/t/net-ftp-questions/68354/3 "2006-09-12T16:51:13Z")

</div>

-----BEGIN PGP SIGNED MESSAGE-----  
Hash: SHA1

Vincent A. wrote:

> 

Yeah, I noticed that after my post… I guess I was trying to  
complicate things 🙂

Thanks,  
Lincoln Anderson  
-----BEGIN PGP SIGNATURE-----  
Version: GnuPG v1.4.2 (MingW32)  
Comment: Using GnuPG with Mozilla - [http://enigmail.mozdev.org](http://enigmail.mozdev.org)

iD8DBQFFBsk+Kte2c0P8BH0RAgagAJ99pzUNbgqd4Xla9/NYxXfCqt7ZJgCfc0qd  
oC7upPw6SIZTOEMr17A66FE=  
=hrJu  
-----END PGP SIGNATURE-----

---

<div class="post-metadata">

**Author:** ![Lincoln\_Anderson](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/e79b87/32.png) [@Lincoln\_Anderson](https://www.ruby-forum.com/u/Lincoln_Anderson)\
**Post date:** [September 12, 2006, 6:47pm UTC](https://www.ruby-forum.com/t/net-ftp-questions/68354/4 "2006-09-12T18:47:29Z")

</div>

Le mercredi 13 septembre 2006 Ã 00:14 +0900, James Cribbs a Ã©crit :  
Lincoln Anderson wrote:

> Here’s where my problem comes in. How can I tell from the list array  
> whether an item is a directory or a file to be copied? Is there  
> something I can use (such as an FTP command) to catch a clue on how to  
> implement this? I know this is possible, as ftpmirror is done with  
> PERL and Ruby can do anything PERL can do - better 🙂

Perhaps this can be useful to browse the FTP server tree (directory  
names finish by ‘/’, others are files):

def recursive\_listing(ftp, path)  
liste\_ftp = Array.new  
list = ftp.ls(path)  
if list.length == 0  
return []  
end  
if list[0].split[0] == ‘total’  
list.delete\_at(0)  
end  
if list[0].split[8] == ‘.’  
list.delete\_at(0)  
end  
if list[0].split[8] == ‘…’  
list.delete\_at(0)  
end  
list.each { |str|  
if str.split[0].index(‘d’) == 0  
liste\_ftp += [path + “/” + str.split[8] + “/”]  
liste\_ftp += [recursive\_listing(ftp, path + “/”

- str.split[8])]  
else  
liste\_ftp += [path + “/” + str.split[8]]  
end  
}  
return liste\_ftp.flatten  
end

ftp = Net::FTP.new(‘ftp\_serveur’)  
ftp.login(‘login’, ‘passwd’)  
ftp\_list = recursive\_listing(ftp, ‘starting\_directory’)  
ftp.close

It might need some corrections depending your FTP server configuration.

Cheers,  
Vincent

---

<div class="post-metadata">

**Author:** ![Lincoln\_Anderson](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/e79b87/32.png) [@Lincoln\_Anderson](https://www.ruby-forum.com/u/Lincoln_Anderson)\
**Post date:** [September 12, 2006, 7:27pm UTC](https://www.ruby-forum.com/t/net-ftp-questions/68354/5 "2006-09-12T19:27:32Z")

</div>

-----BEGIN PGP SIGNED MESSAGE-----  
Hash: SHA1

Vincent A. wrote:

> names finish by ‘/’, others are files):  
> ftp = Net::FTP.new(‘ftp\_serveur’) ftp.login(‘login’, ‘passwd’)

That looks exactly like what I’m trying to do for the directory  
hierarchy mirror. I’m still learning to think in Ruby… I keep going  
back to C/C++ solutions and other heavy hitter languages… I’ll tweak  
that and see if I can get it working. I’ll post my results when I get  
it running (or I have any other insurmountable problems…).

Thanks,  
Lincoln Anderson  
-----BEGIN PGP SIGNATURE-----  
Version: GnuPG v1.4.2 (MingW32)  
Comment: Using GnuPG with Mozilla - [http://enigmail.mozdev.org](http://enigmail.mozdev.org)

iD8DBQFFBu1+Kte2c0P8BH0RAgj9AJ93sCYtnfq8FKx6MmlgGqEYm46RTQCeOi6L  
mkZjNSXuR+vpn1JrgPZORaQ=  
=CfgK  
-----END PGP SIGNATURE-----

---

<div class="post-metadata">

**Author:** ![Lincoln\_Anderson](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/e79b87/32.png) [@Lincoln\_Anderson](https://www.ruby-forum.com/u/Lincoln_Anderson)\
**Post date:** [September 12, 2006, 5:17pm UTC](https://www.ruby-forum.com/t/net-ftp-questions/68354/6 "2006-09-12T17:17:16Z")

</div>

Lincoln Anderson wrote:

> Here’s where my problem comes in. How can I tell from the list array  
> whether an item is a directory or a file to be copied? Is there  
> something I can use (such as an FTP command) to catch a clue on how to  
> implement this? I know this is possible, as ftpmirror is done with  
> PERL and Ruby can do anything PERL can do - better 🙂

Here’s a class I defined to use in a script I run that moves files  
between various Unix and Windows servers at my company. Haven’t looked  
at the code in a while, so it might be ugly, but it works!

class FTPLocation  
def initialize(host, userid, password, path)  
@host, @userid, @password = host, userid, password

```
    if path.nil?
        @path = './'
    else
        @path = path
    end
end

```

#-----------------------------------------------------------------------  
# to\_s

#-----------------------------------------------------------------------  
def to\_s  
return ‘%s - %s’ % [@host, @path]  
end

#-----------------------------------------------------------------------  
# connect

#-----------------------------------------------------------------------  
def connect  
@ftp = Net::FTP.new(@host, @userid, @password)

# @ftp.debug\_mode = true

```
    @ftp.chdir(@path)
end

```

#-----------------------------------------------------------------------  
# empty?

#-----------------------------------------------------------------------  
def empty?  
@ftp.list.each do |entry|  
next if entry[0] == ‘d’  
return false  
end  
return true  
end

#-----------------------------------------------------------------------  
# each\_file

#-----------------------------------------------------------------------  
def each\_file  
t = Time.now  
@ftp.list.each do |entry|  
next if entry[0] == ‘d’  
filename = entry.split(’ ')[-1]  
next if t - @ftp.mtime(filename) \< 300  
yield filename  
end  
end

#-----------------------------------------------------------------------  
# file\_exists?

#-----------------------------------------------------------------------  
def file\_exists?(filename)  
@ftp.list.each do |entry|  
next if entry[0] == ‘d’  
return true if filename == entry.split(’ ')[-1]  
end  
return false  
end

#-----------------------------------------------------------------------  
# get\_file

#-----------------------------------------------------------------------  
def get\_file(filename, dest\_path, xfer\_type)  
if xfer\_type == ‘binary’  
@ftp.getbinaryfile(filename, dest\_path)  
else  
@ftp.gettextfile(filename, dest\_path)  
end  
end

#-----------------------------------------------------------------------  
# put\_file

#-----------------------------------------------------------------------  
def put\_file(source\_path, filename, xfer\_type)  
if xfer\_type == ‘binary’  
@ftp.putbinaryfile(source\_path, filename)  
else  
@ftp.puttextfile(source\_path, filename)  
end  
end

#-----------------------------------------------------------------------  
# delete\_file

#-----------------------------------------------------------------------  
def delete\_file(filename)  
@ftp.delete(filename)  
end

#-----------------------------------------------------------------------  
# close

#-----------------------------------------------------------------------  
def close  
@ftp.close if @ftp  
end  
end

Confidentiality Notice: This email message, including any attachments,  
is for the sole use of the intended recipient(s) and may contain  
confidential and/or privileged information. If you are not the intended  
recipient(s), you are hereby notified that any dissemination,  
unauthorized review, use, disclosure or distribution of this email and  
any materials contained in any attachments is prohibited. If you receive  
this message in error, or are not the intended recipient(s), please  
immediately notify the sender by email and destroy all copies of the  
original message, including attachments.
