класс Net::FTP
Этот класс реализует протокол передачи файлов File Transfer Protocol. Если вы использовали программу FTP в командной строке и знакомы с ее командами, то сможете легко использовать этот класс. В него включены дополнительные функции, использующие стиль и преимущества Ruby.
Пример
require 'net/ftp'
Пример 1
ftp = Net::FTP.new('example.com')
ftp.login
files = ftp.chdir('pub/lang/ruby/contrib')
files = ftp.list('n*')
ftp.getbinaryfile('nif.rb-0.91.gz', 'nif.gz', 1024)
ftp.close
Пример 2
Net::FTP.open('example.com') do |ftp|
ftp.login
files = ftp.chdir('pub/lang/ruby/contrib')
files = ftp.list('n*')
ftp.getbinaryfile('nif.rb-0.91.gz', 'nif.gz', 1024)
end
Основные методы
Ниже приведены методы, которые, скорее всего, будут полезны пользователям:
Атрибуты
Когда true, передачи выполняются в двоичном режиме. По умолчанию: true.
Когда true, весь трафик между сервером и клиентом записывается в +$stdout+. По умолчанию: false.
Последний ответ сервера.
Код последнего ответа сервера.
Код последнего ответа сервера.
Количество секунд ожидания открытия соединения. Может быть использовано любое число, включая дробные значения. Если объект FTP не может открыть соединение за это время, он генерирует исключение Net::OpenTimeout. Значение по умолчанию — nil.
Когда true, соединение находится в пассивном режиме. По умолчанию: false.
Количество секунд ожидания чтения одного блока (с помощью одной вызова read(2)). Может быть использовано любое число, включая дробные значения. Если объект FTP не может прочитать данные за это время, он генерирует исключение Timeout::Error. Значение по умолчанию — 60 секунд.
Устанавливает или получает состояние resume, которое определяет, будут ли возобновляться или перезапускаться неполные передачи. По умолчанию: false.
Приветственное сообщение сервера.
Публичные методы класса
# File lib/net/ftp.rb, line 149
def initialize(host = nil, user = nil, passwd = nil, acct = nil)
super()
@binary = true
@passive = false
@debug_mode = false
@resume = false
@sock = NullSocket.new
@logged_in = false
@open_timeout = nil
@read_timeout = 60
if host
connect(host)
if user
login(user, passwd, acct)
end
end
end Создает и возвращает новый объект FTP. Если задан параметр host, соединение устанавливается. Кроме того, если заданы user, используется заданное имя пользователя, пароль и (необязательно) учетная запись для входа. См. login.
# File lib/net/ftp.rb, line 131
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 Синоним для FTP.new, но с обязательным параметром host.
Если задан блок, он передается объекту FTP , который будет закрыт по завершении блока или при возникновении исключения.
Публичные методы экземпляра
# File lib/net/ftp.rb, line 880
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 Прерывает предыдущую команду (команда ABOR).
# File lib/net/ftp.rb, line 732 def acct(account) cmd = "ACCT " + account voidcmd(cmd) end
Отправляет команду ACCT.
Это менее распространённая команда FTP, для отправки информации об учётной записи, если удалённый хост этого требует.
# File lib/net/ftp.rb, line 169
def binary=(newmode)
if newmode != @binary
@binary = newmode
send_type_command if @logged_in
end
end Установка для переключения режимов передачи в бинарном режиме. newmode может быть либо true, либо false
# File lib/net/ftp.rb, line 802
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 Изменяет (удаленный) каталог.
# File lib/net/ftp.rb, line 953
def close
if @sock and not @sock.closed?
begin
@sock.shutdown(Socket::SHUT_WR) rescue nil
orig, self.read_timeout = self.read_timeout, 3
@sock.read rescue nil
ensure
@sock.close
self.read_timeout = orig
end
end
end Закрывает соединение. Дальнейшие операции невозможны, пока вы не откроете новое соединение с помощью connect.
# File lib/net/ftp.rb, line 969 def closed? @sock == nil or @sock.closed? end
Возвращает true, если соединение закрыто.
# File lib/net/ftp.rb, line 243
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 Устанавливает FTP соединение с хостом, при необходимости переопределяя порт по умолчанию. Если переменная окружения SOCKS_SERVER установлена, устанавливает соединение через прокси SOCKS. Вызывает исключение (обычно Errno::ECONNREFUSED) если соединение не может быть установлено.
# File lib/net/ftp.rb, line 788
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 Удаляет файл на сервере.
# File lib/net/ftp.rb, line 661
def get(remotefile, localfile = File.basename(remotefile),
blocksize = DEFAULT_BLOCKSIZE, &block) # :yield: data
if @binary
getbinaryfile(remotefile, localfile, blocksize, &block)
else
gettextfile(remotefile, localfile, &block)
end
end Извлекает remotefile в том режиме, в котором установлен сеанс (текстовый или бинарный). Смотрите gettextfile и getbinaryfile.
# File lib/net/ftp.rb, line 603
def getbinaryfile(remotefile, localfile = File.basename(remotefile),
blocksize = DEFAULT_BLOCKSIZE) # :yield: data
result = nil
if localfile
if @resume
rest_offset = File.size?(localfile)
f = File.open(localfile, "a")
else
rest_offset = nil
f = File.open(localfile, "w")
end
elsif !block_given?
result = ""
end
begin
f.binmode if localfile
retrbinary("RETR " + remotefile.to_s, blocksize, rest_offset) do |data|
f.write(data) if localfile
yield(data) if block_given?
result.concat(data) if result
end
return result
ensure
f.close if localfile
end
end Извлекает remotefile в бинарном режиме, сохраняя результат в localfile. Если localfile равно nil, возвращает извлеченные данные. Если предоставлен блок, ему передаются извлеченные данные в виде фрагментов размером blocksize.
# File lib/net/ftp.rb, line 637
def gettextfile(remotefile, localfile = File.basename(remotefile)) # :yield: line
result = nil
if localfile
f = File.open(localfile, "w")
elsif !block_given?
result = ""
end
begin
retrlines("RETR " + remotefile) do |line, newline|
l = newline ? line + "\n" : line
f.print(l) if localfile
yield(line, newline) if block_given?
result.concat(l) if result
end
return result
ensure
f.close if localfile
end
end Извлекает remotefile в режиме ASCII (текстовом), сохраняя результат в localfile. Если localfile равно nil, возвращает извлеченные данные. Если предоставлен блок, ему передаются извлеченные данные построчно.
# File lib/net/ftp.rb, line 917
def help(arg = nil)
cmd = "HELP"
if arg
cmd = cmd + " " + arg
end
sendcmd(cmd)
end Выполняет команду HELP.
# File lib/net/ftp.rb, line 756
def list(*args, &block) # :yield: line
cmd = "LIST"
args.each do |arg|
cmd = cmd + " " + arg.to_s
end
if block
retrlines(cmd, &block)
else
lines = []
retrlines(cmd) do |line|
lines << line
end
return lines
end
end Возвращает массив информации о файлах в каталоге (вывод похож на `ls -l`). Если задан блок, он перебирает список.
# File lib/net/ftp.rb, line 454
def login(user = "anonymous", passwd = nil, acct = nil)
if user == "anonymous" and passwd == nil
passwd = "anonymous@"
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
send_type_command
@logged_in = true
end Авторизуется на удаленном хосте. Сеанс должен быть предварительно подключен. Если user это строка “anonymous” и password это nil, то в качестве пароля используется “anonymous@”. Если параметр acct не nil, то после успешной авторизации отправляется команда FTP ACCT. Вызывает исключение при ошибке (обычно Net::FTPPermError).
# File lib/net/ftp.rb, line 907
def mdtm(filename)
resp = sendcmd("MDTM " + filename)
if resp[0, 3] == "213"
return resp[3 .. -1].strip
end
end Возвращает необработанное время последнего изменения (удаленного) файла в формате “YYYYMMDDhhmmss” (команда MDTM).
Используйте mtime, если вам нужен разобранный экземпляр Time.
# File lib/net/ftp.rb, line 845
def mkdir(dirname)
resp = sendcmd("MKD " + dirname)
return parse257(resp)
end Создает удаленный каталог.
# File lib/net/ftp.rb, line 836
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 Возвращает время последнего изменения (удаленного) файла. Если local это true, оно возвращается как локальное время, в противном случае это время UTC.
# File lib/net/ftp.rb, line 740
def nlst(dir = nil)
cmd = "NLST"
if dir
cmd = cmd + " " + dir
end
files = []
retrlines(cmd) do |line|
files.push(line)
end
return files
end Возвращает массив имен файлов в удаленном каталоге.
# File lib/net/ftp.rb, line 937
def noop
voidcmd("NOOP")
end Выполняет команду NOOP.
Ничего не делает, кроме возвращения ответа.
# File lib/net/ftp.rb, line 717
def put(localfile, remotefile = File.basename(localfile),
blocksize = DEFAULT_BLOCKSIZE, &block)
if @binary
putbinaryfile(localfile, remotefile, blocksize, &block)
else
puttextfile(localfile, remotefile, &block)
end
end Переносит localfile на сервер в том режиме, в котором установлен сеанс (текстовый или бинарный). Смотрите puttextfile и putbinaryfile.
# File lib/net/ftp.rb, line 675
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 = File.open(localfile)
begin
f.binmode
if rest_offset
storbinary("APPE " + remotefile, f, blocksize, rest_offset, &block)
else
storbinary("STOR " + remotefile, f, blocksize, rest_offset, &block)
end
ensure
f.close
end
end Переносит localfile на сервер в двоичном режиме, сохраняя результат в remotefile. Если задан блок, вызывается этот блок, передавая данные, переданные в blocksize фрагментах.
# File lib/net/ftp.rb, line 704
def puttextfile(localfile, remotefile = File.basename(localfile), &block) # :yield: line
f = File.open(localfile)
begin
storlines("STOR " + remotefile, f, &block)
ensure
f.close
end
end Переносит localfile на сервер в ASCII (текстовом) режиме, сохраняя результат в remotefile. Если задан обратный вызов или связанный блок, вызывается этот блок, передавая передаваемые данные по одной строке за раз.
# File lib/net/ftp.rb, line 860
def pwd
resp = sendcmd("PWD")
return parse257(resp)
end Возвращает текущую удалённую директорию.
# File lib/net/ftp.rb, line 928
def quit
voidcmd("QUIT")
end Выходит из сессии FTP.
# File lib/net/ftp.rb, line 110 def read_timeout=(sec) @sock.read_timeout = sec @read_timeout = sec end
Метод установки атрибута #read_timeout.
# File lib/net/ftp.rb, line 777
def rename(fromname, toname)
resp = sendcmd("RNFR " + fromname)
if resp[0] != ?3
raise FTPReplyError, resp
end
voidcmd("RNTO " + toname)
end Переименовывает файл на сервере.
# File lib/net/ftp.rb, line 485
def retrbinary(cmd, blocksize, rest_offset = nil) # :yield: data
synchronize do
with_binary(true) do
begin
conn = transfercmd(cmd, rest_offset)
loop do
data = conn.read(blocksize)
break if data == nil
yield(data)
end
conn.shutdown(Socket::SHUT_WR)
conn.read_timeout = 1
conn.read
ensure
conn.close if conn
end
voidresp
end
end
end Переводит соединение в двоичный (графический) режим, выполняет заданную команду и извлекает возвращаемые данные, передавая их связанному блоку частями по blocksize символов. Обратите внимание, что cmd — это команда сервера (например, «RETR myfile»).
# File lib/net/ftp.rb, line 512
def retrlines(cmd) # :yield: line
synchronize do
with_binary(false) do
begin
conn = transfercmd(cmd)
loop do
line = conn.gets
break if line == nil
yield(line.sub(/\r?\n\z/, ""), !line.match(/\n\z/).nil?)
end
conn.shutdown(Socket::SHUT_WR)
conn.read_timeout = 1
conn.read
ensure
conn.close if conn
end
voidresp
end
end
end Переводит соединение в ASCII (текстовый) режим, выполняет заданную команду и передает полученные данные по одной строке за раз в связанный блок. Если блок не задан, строки выводятся на экран. Обратите внимание, что cmd — это команда сервера (например, «RETR myfile»).
# File lib/net/ftp.rb, line 853
def rmdir(dirname)
voidcmd("RMD " + dirname)
end Удаляет удалённую директорию.
# File lib/net/ftp.rb, line 352
def sendcmd(cmd)
synchronize do
putline(cmd)
return getresp
end
end Отправляет команду и возвращает ответ.
# File lib/net/ftp.rb, line 257
def set_socket(sock, get_greeting = true)
synchronize do
@sock = sock
if get_greeting
voidresp
end
end
end Устанавливает сокет, используемый для подключения к серверу FTP.
Может вызывать FTPReplyError, если get_greeting равно false.
# File lib/net/ftp.rb, line 944 def site(arg) cmd = "SITE " + arg voidcmd(cmd) end
Выполняет команду SITE.
# File lib/net/ftp.rb, line 820
def size(filename)
with_binary(true) do
resp = sendcmd("SIZE " + filename)
if resp[0, 3] != "213"
raise FTPReplyError, resp
end
return resp[3..-1].strip.to_i
end
end Возвращает размер указанного (удаленного) файла.
# File lib/net/ftp.rb, line 894 def status line = "STAT" + CRLF print "put: STAT\n" if @debug_mode @sock.send(line, Socket::MSG_OOB) return getresp end
Возвращает статус (команда STAT).
# File lib/net/ftp.rb, line 539
def storbinary(cmd, file, blocksize, rest_offset = nil) # :yield: data
if rest_offset
file.seek(rest_offset, IO::SEEK_SET)
end
synchronize do
with_binary(true) do
conn = transfercmd(cmd)
loop do
buf = file.read(blocksize)
break if buf == nil
conn.write(buf)
yield(buf) if block_given?
end
conn.close
voidresp
end
end
rescue Errno::EPIPE
# EPIPE, in this case, means that the data connection was unexpectedly
# terminated. Rather than just raising EPIPE to the caller, check the
# response on the control connection. If getresp doesn't raise a more
# appropriate exception, re-raise the original exception.
getresp
raise
end Переводит соединение в двоичный (графический) режим, выполняет заданную команду сервера (например, «STOR myfile») и отправляет содержимое файла с именем file на сервер. Если задан необязательный блок, он также передает ему данные частями по blocksize символов.
# File lib/net/ftp.rb, line 571
def storlines(cmd, file) # :yield: line
synchronize do
with_binary(false) do
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_given?
end
conn.close
voidresp
end
end
rescue Errno::EPIPE
# EPIPE, in this case, means that the data connection was unexpectedly
# terminated. Rather than just raising EPIPE to the caller, check the
# response on the control connection. If getresp doesn't raise a more
# appropriate exception, re-raise the original exception.
getresp
raise
end Переводит соединение в ASCII (текстовый) режим, выполняет заданную команду сервера (например, «STOR myfile») и отправляет содержимое файла с именем file на сервер по одной строке за раз. Если задан необязательный блок, он также передает ему строки.
# File lib/net/ftp.rb, line 869
def system
resp = sendcmd("SYST")
if resp[0, 3] != "215"
raise FTPReplyError, resp
end
return resp[4 .. -1]
end Возвращает системную информацию.
# File lib/net/ftp.rb, line 362
def voidcmd(cmd)
synchronize do
putline(cmd)
voidresp
end
end Отправляет команду и ожидает ответа, начинающегося с '2'.
Методы частного экземпляра
# File lib/net/ftp.rb, line 1007
def parse_pasv_ipv4_host(s)
return s.tr(",", ".")
end # File lib/net/ftp.rb, line 1012
def parse_pasv_ipv6_host(s)
return s.split(/,/).map { |i|
"%02x" % i.to_i
}.each_slice(2).map(&:join).join(":")
end # File lib/net/ftp.rb, line 1019
def parse_pasv_port(s)
return s.split(/,/).map(&:to_i).inject { |x, y|
(x << 8) + y
}
end
Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.