Ruby FTP Отделение файлов от папок - PullRequest
6 голосов
/ 04 марта 2012

Я пытаюсь сканировать FTP и рекурсивно опускать все файлы.

До сих пор я пытался вытащить каталог с помощью

   ftp.list.each do |entry|
    if entry.split(/\s+/)[0][0, 1] == "d"
      out[:dirs] << entry.split.last unless black_dirs.include? entry.split.last
    else
      out[:files] << entry.split.last unless black_files.include? entry.split.last
    end

Но получается, что если вы разделяете список до последнего пробела, имена файлов и каталоги с пробелами выбираются неправильно.Здесь нужна небольшая помощь по логике.

Ответы [ 5 ]

4 голосов
/ 04 марта 2012

Вы можете избежать рекурсии, если перечисляете все файлы одновременно

files = ftp.nlst('**/*.*')

Каталоги не включены в список, но полный путь к FTP по-прежнему доступен в имени.

EDIT

Я предполагаю, что каждое имя файла содержит точку, а имена каталогов - нет. Спасибо за упоминание @Niklas B.

3 голосов
/ 10 апреля 2012

Вокруг огромное количество FTP-серверов.

У нас есть клиенты, которые используют некоторые непонятные проприетарные серверы на базе Windows, и возвращаемый ими список файлов выглядит совершенно иначе, чем в версиях Linux.

Итак, что я закончил, так это для каждой записи файла / каталога, я пытаюсь сменить каталог на него, и если это не работает - считайте это файлом:)

Следующий метод является «пуленепробиваемым»:

# Checks if the give file_name is actually a file.
def is_ftp_file?(ftp, file_name)
  ftp.chdir(file_name)
  ftp.chdir('..')
  false
rescue
  true
end

file_names = ftp.nlst.select {|fname| is_ftp_file?(ftp, fname)}

Работает как шарм, но обратите внимание: , если в каталоге FTP есть тонны файлов - этот метод занимает некоторое время , чтобы пройти все из них.

2 голосов
/ 07 августа 2012

При условии, что FTP-сервер возвращает Unix-подобные списки файлов, работает следующий код. По крайней мере, для меня.

regex = /^d[r|w|x|-]+\s+[0-9]\s+\S+\s+\S+\s+\d+\s+\w+\s+\d+\s+[\d|:]+\s(.+)/
ftp.ls.each do |line|
    if dir = line.match(regex)
        puts dir[1]
    end
end

dir[1] содержит имя каталога (учитывая, что проверенная строка фактически представляет каталог).

2 голосов
/ 04 марта 2012

Вы также можете использовать регулярное выражение. Я положил один вместе. Пожалуйста, убедитесь, что это работает для вас, а я не знаю, что ваша директория выглядит иначе. Вы должны использовать Ruby 1.9 между прочим.

reg = /^(?<type>.{1})(?<mode>\S+)\s+(?<number>\d+)\s+(?<owner>\S+)\s+(?<group>\S+)\s+(?<size>\d+)\s+(?<mod_time>.{12})\s+(?<path>.+)$/

match = entry.match(reg)

Вы можете получить доступ к элементам по имени, тогда

match[:type] содержит 'd', если это каталог, пробел, если это файл.

Все остальные элементы тоже есть. Самое главное match[:path].

0 голосов
/ 14 сентября 2015

Как отметил @Alex, использование шаблонов в именах файлов для этого вряд ли надежно.Каталоги могут иметь точки в своих именах (например, .ssh), и списки могут сильно отличаться на разных серверах.

Его метод работает, но, как он сам указывает, занимает слишком много времени.Я предпочитаю использовать метод .size из Net :: FTP.Возвращает размер файла или выдает ошибку, если файл является каталогом.

def item_is_file? (item)
    ftp = Net::FTP.new(host, username, password)
    begin 
    if ftp.size(item).is_a? Numeric
        true
    end
    rescue Net::FTPPermError
        return false
    end
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...