Class: Net::FTP

Inherits:
Object
  • Object
show all
Includes:
MonitorMixin
Defined in:
lib/net/ftp.rb

Overview

This class implements the File Transfer Protocol. If you have used a command-line FTP program, and are familiar with the commands, you will be able to use this class easily. Some extra features are included to take advantage of Ruby's style and strengths.

Example

require 'net/ftp'

Example 1

ftp = Net::FTP.new('ftp.netlab.co.jp')
ftp.
files = ftp.chdir('pub/lang/ruby/contrib')
files = ftp.list('n*')
ftp.getbinaryfile('nif.rb-0.91.gz', 'nif.gz', 1024)
ftp.close

Example 2

Net::FTP.open('ftp.netlab.co.jp') do |ftp|
  ftp.
  files = ftp.chdir('pub/lang/ruby/contrib')
  files = ftp.list('n*')
  ftp.getbinaryfile('nif.rb-0.91.gz', 'nif.gz', 1024)
end

Major Methods

The following are the methods most likely to be useful to users:

  • FTP.open

  • #getbinaryfile

  • #gettextfile

  • #putbinaryfile

  • #puttextfile

  • #chdir

  • #nlst

  • #size

  • #rename

  • #delete

Constant Summary collapse

FTP_PORT =

:stopdoc:

21
CRLF =
"\r\n"
DEFAULT_BLOCKSIZE =
4096
MDTM_REGEXP =

:nodoc:

/^(\d\d\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)/

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(host = nil, user = nil, passwd = nil, acct = nil) ⇒ FTP

Creates and returns a new FTP object. If a host is given, a connection is made. Additionally, if the user is given, the given user name, password, and (optionally) account are used to log in. See #login.



129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/net/ftp.rb', line 129

def initialize(host = nil, user = nil, passwd = nil, acct = nil)
  super()
  @binary = true
  @passive = false
  @debug_mode = false
  @resume = false
  if host
	connect(host)
	if user
	  (user, passwd, acct)
	end
  end
end

Instance Attribute Details

#binaryObject

When true, transfers are performed in binary mode. Default: true.



82
83
84
# File 'lib/net/ftp.rb', line 82

def binary
  @binary
end

#debug_modeObject

When true, all traffic to and from the server is written to $stdout. Default: false.



89
90
91
# File 'lib/net/ftp.rb', line 89

def debug_mode
  @debug_mode
end

#last_responseObject (readonly)

The server's last response.



103
104
105
# File 'lib/net/ftp.rb', line 103

def last_response
  @last_response
end

#last_response_codeObject (readonly) Also known as: lastresp

The server's last response code.



99
100
101
# File 'lib/net/ftp.rb', line 99

def last_response_code
  @last_response_code
end

#passiveObject

When true, the connection is in passive mode. Default: false.



85
86
87
# File 'lib/net/ftp.rb', line 85

def passive
  @passive
end

#resumeObject

Sets or retrieves the resume status, which decides whether incomplete transfers are resumed or restarted. Default: false.



93
94
95
# File 'lib/net/ftp.rb', line 93

def resume
  @resume
end

#welcomeObject (readonly)

The server's welcome message.



96
97
98
# File 'lib/net/ftp.rb', line 96

def welcome
  @welcome
end

Class Method Details

.open(host, user = nil, passwd = nil, acct = nil) ⇒ Object

A synonym for FTP.new, but with a mandatory host parameter.

If a block is given, it is passed the FTP object, which will be closed when the block finishes, or when an exception is raised.



111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/net/ftp.rb', line 111

def FTP.open(host, user = nil, passwd = nil, acct = nil)
  if block_given?
    ftp = new(host, user, passwd, acct)
    begin
      yield ftp
    ensure
      ftp.close
    end
  else
    new(host, user, passwd, acct)
  end
end

Instance Method Details

#abortObject

Aborts the previous command (ABOR command).



745
746
747
748
749
750
751
752
753
754
# File 'lib/net/ftp.rb', line 745

def abort
  line = "ABOR" + CRLF
  print "put: ABOR\n" if @debug_mode
  @sock.send(line, Socket::MSG_OOB)
  resp = getmultiline
  unless ["426", "226", "225"].include?(resp[0, 3])
	raise FTPProtoError, resp
  end
  return resp
end

#acct(account) ⇒ Object

Sends the ACCT command. TODO: more info.



598
599
600
601
# File 'lib/net/ftp.rb', line 598

def acct()
  cmd = "ACCT " + 
  voidcmd(cmd)
end

#chdir(dirname) ⇒ Object

Changes the (remote) directory.



668
669
670
671
672
673
674
675
676
677
678
679
680
681
# File 'lib/net/ftp.rb', line 668

def chdir(dirname)
  if dirname == ".."
	begin
	  voidcmd("CDUP")
	  return
	rescue FTPPermError => e
	  if e.message[0, 3] != "500"
 raise e
	  end
	end
  end
  cmd = "CWD " + dirname
  voidcmd(cmd)
end

#closeObject

Closes the connection. Further operations are impossible until you open a new connection with #connect.



813
814
815
# File 'lib/net/ftp.rb', line 813

def close
  @sock.close if @sock and not @sock.closed?
end

#closed?Boolean

Returns true iff the connection is closed.

Returns:

  • (Boolean)


820
821
822
# File 'lib/net/ftp.rb', line 820

def closed?
  @sock == nil or @sock.closed?
end

#connect(host, port = FTP_PORT) ⇒ Object

Establishes an FTP connection to host, optionally overriding the default port. If the environment variable SOCKS_SERVER is set, sets up the connection through a SOCKS proxy. Raises an exception (typically Errno::ECONNREFUSED) if the connection cannot be established.



170
171
172
173
174
175
176
177
178
# File 'lib/net/ftp.rb', line 170

def connect(host, port = FTP_PORT)
  if @debug_mode
	print "connect: ", host, ", ", port, "\n"
  end
  synchronize do
	@sock = open_socket(host, port)
	voidresp
  end
end

#delete(filename) ⇒ Object

Deletes a file on the server.



654
655
656
657
658
659
660
661
662
663
# File 'lib/net/ftp.rb', line 654

def delete(filename)
  resp = sendcmd("DELE " + filename)
  if resp[0, 3] == "250"
	return
  elsif resp[0] == ?5
	raise FTPPermError, resp
  else
	raise FTPReplyError, resp
  end
end

#get(remotefile, localfile = File.basename(remotefile), blocksize = DEFAULT_BLOCKSIZE, &block) ⇒ Object

Retrieves remotefile in whatever mode the session is set (text or binary). See #gettextfile and #getbinaryfile.



534
535
536
537
538
539
540
541
# File 'lib/net/ftp.rb', line 534

def get(remotefile, localfile = File.basename(remotefile),
 blocksize = DEFAULT_BLOCKSIZE, &block) # :yield: data
  unless @binary
	gettextfile(remotefile, localfile, &block)
  else
	getbinaryfile(remotefile, localfile, blocksize, &block)
  end
end

#getbinaryfile(remotefile, localfile = File.basename(remotefile), blocksize = DEFAULT_BLOCKSIZE, &block) ⇒ Object

Retrieves remotefile in binary mode, storing the result in localfile. If a block is supplied, it is passed the retrieved data in blocksize chunks.



493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
# File 'lib/net/ftp.rb', line 493

def getbinaryfile(remotefile, localfile = File.basename(remotefile),
    blocksize = DEFAULT_BLOCKSIZE, &block) # :yield: data
  if @resume
	rest_offset = File.size?(localfile)
	f = open(localfile, "a")
  else
	rest_offset = nil
	f = open(localfile, "w")
  end
  begin
	f.binmode
	retrbinary("RETR " + remotefile, blocksize, rest_offset) do |data|
	  f.write(data)
	  yield(data) if block
	end
  ensure
	f.close
  end
end

#gettextfile(remotefile, localfile = File.basename(remotefile), &block) ⇒ Object

Retrieves remotefile in ASCII (text) mode, storing the result in localfile. If a block is supplied, it is passed the retrieved data one line at a time.



518
519
520
521
522
523
524
525
526
527
528
# File 'lib/net/ftp.rb', line 518

def gettextfile(remotefile, localfile = File.basename(remotefile), &block) # :yield: line
  f = open(localfile, "w")
  begin
	retrlines("RETR " + remotefile) do |line|
	  f.puts(line)
	  yield(line) if block
	end
  ensure
	f.close
  end
end

#help(arg = nil) ⇒ Object

Issues the HELP command.



779
780
781
782
783
784
785
# File 'lib/net/ftp.rb', line 779

def help(arg = nil)
  cmd = "HELP"
  if arg
	cmd = cmd + " " + arg
  end
  sendcmd(cmd)
end

#list(*args, &block) ⇒ Object Also known as: ls, dir

Returns an array of file information in the directory (the output is like 'ls -l`). If a block is given, it iterates through the listing.



622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
# File 'lib/net/ftp.rb', line 622

def list(*args, &block) # :yield: line
  cmd = "LIST"
  args.each do |arg|
	cmd = cmd + " " + arg
  end
  if block
	retrlines(cmd, &block)
  else
	lines = []
	retrlines(cmd) do |line|
	  lines << line
	end
	return lines
  end
end

#login(user = "anonymous", passwd = nil, acct = nil) ⇒ Object

Logs in to the remote host. The session must have been previously connected. If user is the string "anonymous" and the password is nil, a password of user@host is synthesized. If the acct parameter is not nil, an FTP ACCT command is sent following the successful login. Raises an exception on error (typically Net::FTPPermError).



372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
# File 'lib/net/ftp.rb', line 372

def (user = "anonymous", passwd = nil, acct = nil)
  if user == "anonymous" and passwd == nil
	passwd = getaddress
  end
  
  resp = ""
  synchronize do
	resp = sendcmd('USER ' + user)
	if resp[0] == ?3
      raise FTPReplyError, resp if passwd.nil?
	  resp = sendcmd('PASS ' + passwd)
	end
	if resp[0] == ?3
      raise FTPReplyError, resp if acct.nil?
	  resp = sendcmd('ACCT ' + acct)
	end
  end
  if resp[0] != ?2
	raise FTPReplyError, resp
  end
  @welcome = resp
end

#mdtm(filename) ⇒ Object

Issues the MDTM command. TODO: more info.



769
770
771
772
773
774
# File 'lib/net/ftp.rb', line 769

def mdtm(filename)
  resp = sendcmd("MDTM " + filename)
  if resp[0, 3] == "213"
	return resp[3 .. -1].strip
  end
end

#mkdir(dirname) ⇒ Object

Creates a remote directory.



710
711
712
713
# File 'lib/net/ftp.rb', line 710

def mkdir(dirname)
  resp = sendcmd("MKD " + dirname)
  return parse257(resp)
end

#mtime(filename, local = false) ⇒ Object

Returns the last modification time of the (remote) file. If local is true, it is returned as a local time, otherwise it's a UTC time.



701
702
703
704
705
# File 'lib/net/ftp.rb', line 701

def mtime(filename, local = false)
  str = mdtm(filename)
  ary = str.scan(MDTM_REGEXP)[0].collect {|i| i.to_i}
  return local ? Time.local(*ary) : Time.gm(*ary)
end

#nlst(dir = nil) ⇒ Object

Returns an array of filenames in the remote directory.



606
607
608
609
610
611
612
613
614
615
616
# File 'lib/net/ftp.rb', line 606

def nlst(dir = nil)
  cmd = "NLST"
  if dir
	cmd = cmd + " " + dir
  end
  files = []
  retrlines(cmd) do |line|
	files.push(line)
  end
  return files
end

#noopObject

Issues a NOOP command.



797
798
799
# File 'lib/net/ftp.rb', line 797

def noop
  voidcmd("NOOP")
end

#put(localfile, remotefile = File.basename(localfile), blocksize = DEFAULT_BLOCKSIZE, &block) ⇒ Object

Transfers localfile to the server in whatever mode the session is set (text or binary). See #puttextfile and #putbinaryfile.



586
587
588
589
590
591
592
593
# File 'lib/net/ftp.rb', line 586

def put(localfile, remotefile = File.basename(localfile),
 blocksize = DEFAULT_BLOCKSIZE, &block)
  unless @binary
	puttextfile(localfile, remotefile, &block)
  else
	putbinaryfile(localfile, remotefile, blocksize, &block)
  end
end

#putbinaryfile(localfile, remotefile = File.basename(localfile), blocksize = DEFAULT_BLOCKSIZE, &block) ⇒ Object

Transfers localfile to the server in binary mode, storing the result in remotefile. If a block is supplied, calls it, passing in the transmitted data in blocksize chunks.



548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
# File 'lib/net/ftp.rb', line 548

def putbinaryfile(localfile, remotefile = File.basename(localfile),
    blocksize = DEFAULT_BLOCKSIZE, &block) # :yield: data
  if @resume
    begin
      rest_offset = size(remotefile)
    rescue Net::FTPPermError
      rest_offset = nil
    end
  else
	rest_offset = nil
  end
  f = open(localfile)
  begin
	f.binmode
	storbinary("STOR " + remotefile, f, blocksize, rest_offset, &block)
  ensure
	f.close
  end
end

#puttextfile(localfile, remotefile = File.basename(localfile), &block) ⇒ Object

Transfers localfile to the server in ASCII (text) mode, storing the result in remotefile. If callback or an associated block is supplied, calls it, passing in the transmitted data one line at a time.



573
574
575
576
577
578
579
580
# File 'lib/net/ftp.rb', line 573

def puttextfile(localfile, remotefile = File.basename(localfile), &block) # :yield: line
  f = open(localfile)
  begin
	storlines("STOR " + remotefile, f, &block)
  ensure
	f.close
  end
end

#pwdObject Also known as: getdir

Returns the current remote directory.



725
726
727
728
# File 'lib/net/ftp.rb', line 725

def pwd
  resp = sendcmd("PWD")
  return parse257(resp)
end

#quitObject

Exits the FTP session.



790
791
792
# File 'lib/net/ftp.rb', line 790

def quit
  voidcmd("QUIT")
end

#rename(fromname, toname) ⇒ Object

Renames a file on the server.



643
644
645
646
647
648
649
# File 'lib/net/ftp.rb', line 643

def rename(fromname, toname)
  resp = sendcmd("RNFR " + fromname)
  if resp[0] != ?3
	raise FTPReplyError, resp
  end
  voidcmd("RNTO " + toname)
end

#retrbinary(cmd, blocksize, rest_offset = nil) ⇒ Object

Puts the connection into binary (image) mode, issues the given command, and fetches the data returned, passing it to the associated block in chunks of blocksize characters. Note that cmd is a server command (such as "RETR myfile").



401
402
403
404
405
406
407
408
409
410
411
412
413
# File 'lib/net/ftp.rb', line 401

def retrbinary(cmd, blocksize, rest_offset = nil) # :yield: data
  synchronize do
	voidcmd("TYPE I")
	conn = transfercmd(cmd, rest_offset)
	loop do
	  data = conn.read(blocksize)
	  break if data == nil
	  yield(data)
	end
	conn.close
	voidresp
  end
end

#retrlines(cmd) ⇒ Object

Puts the connection into ASCII (text) mode, issues the given command, and passes the resulting data, one line at a time, to the associated block. If no block is given, prints the lines. Note that cmd is a server command (such as "RETR myfile").



421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
# File 'lib/net/ftp.rb', line 421

def retrlines(cmd) # :yield: line
  synchronize do
	voidcmd("TYPE A")
	conn = transfercmd(cmd)
	loop do
	  line = conn.gets
	  break if line == nil
	  if line[-2, 2] == CRLF
 line = line[0 .. -3]
	  elsif line[-1] == ?\n
 line = line[0 .. -2]
	  end
	  yield(line)
	end
	conn.close
	voidresp
  end
end

#return_codeObject

Obsolete



144
145
146
147
# File 'lib/net/ftp.rb', line 144

def return_code
  $stderr.puts("warning: Net::FTP#return_code is obsolete and do nothing")
  return "\n"
end

#return_code=(s) ⇒ Object

Obsolete



150
151
152
# File 'lib/net/ftp.rb', line 150

def return_code=(s)
  $stderr.puts("warning: Net::FTP#return_code= is obsolete and do nothing")
end

#rmdir(dirname) ⇒ Object

Removes a remote directory.



718
719
720
# File 'lib/net/ftp.rb', line 718

def rmdir(dirname)
  voidcmd("RMD " + dirname)
end

#sendcmd(cmd) ⇒ Object

Sends a command and returns the response.



261
262
263
264
265
266
# File 'lib/net/ftp.rb', line 261

def sendcmd(cmd)
  synchronize do
	putline(cmd)
	return getresp
  end
end

#set_socket(sock, get_greeting = true) ⇒ Object

WRITEME or make private



183
184
185
186
187
188
189
190
# File 'lib/net/ftp.rb', line 183

def set_socket(sock, get_greeting = true)
  synchronize do
	@sock = sock
	if get_greeting
	  voidresp
	end
  end
end

#site(arg) ⇒ Object

Issues a SITE command.



804
805
806
807
# File 'lib/net/ftp.rb', line 804

def site(arg)
  cmd = "SITE " + arg
  voidcmd(cmd)
end

#size(filename) ⇒ Object

Returns the size of the given (remote) filename.



686
687
688
689
690
691
692
693
# File 'lib/net/ftp.rb', line 686

def size(filename)
  voidcmd("TYPE I")
  resp = sendcmd("SIZE " + filename)
  if resp[0, 3] != "213" 
	raise FTPReplyError, resp
  end
  return resp[3..-1].strip.to_i
end

#statusObject

Returns the status (STAT command).



759
760
761
762
763
764
# File 'lib/net/ftp.rb', line 759

def status
  line = "STAT" + CRLF
  print "put: STAT\n" if @debug_mode
  @sock.send(line, Socket::MSG_OOB)
  return getresp
end

#storbinary(cmd, file, blocksize, rest_offset = nil, &block) ⇒ Object

Puts the connection into binary (image) mode, issues the given server-side command (such as "STOR myfile"), and sends the contents of the file named file to the server. If the optional block is given, it also passes it the data, in chunks of blocksize characters.



446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
# File 'lib/net/ftp.rb', line 446

def storbinary(cmd, file, blocksize, rest_offset = nil, &block) # :yield: data
  if rest_offset
    file.seek(rest_offset, IO::SEEK_SET)
  end
  synchronize do
	voidcmd("TYPE I")
	conn = transfercmd(cmd, rest_offset)
	loop do
	  buf = file.read(blocksize)
	  break if buf == nil
	  conn.write(buf)
	  yield(buf) if block
	end
	conn.close
	voidresp
  end
end

#storlines(cmd, file, &block) ⇒ Object

Puts the connection into ASCII (text) mode, issues the given server-side command (such as "STOR myfile"), and sends the contents of the file named file to the server, one line at a time. If the optional block is given, it also passes it the lines.



470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
# File 'lib/net/ftp.rb', line 470

def storlines(cmd, file, &block) # :yield: line
  synchronize do
	voidcmd("TYPE A")
	conn = transfercmd(cmd)
	loop do
	  buf = file.gets
	  break if buf == nil
	  if buf[-2, 2] != CRLF
 buf = buf.chomp + CRLF
	  end
	  conn.write(buf)
	  yield(buf) if block
	end
	conn.close
	voidresp
  end
end

#systemObject

Returns system information.



734
735
736
737
738
739
740
# File 'lib/net/ftp.rb', line 734

def system
  resp = sendcmd("SYST")
  if resp[0, 3] != "215"
	raise FTPReplyError, resp
  end
  return resp[4 .. -1]
end

#voidcmd(cmd) ⇒ Object

Sends a command and expect a response beginning with '2'.



271
272
273
274
275
276
# File 'lib/net/ftp.rb', line 271

def voidcmd(cmd)
  synchronize do
	putline(cmd)
	voidresp
  end
end