2012-03-04 8 views
6

Próbuję zaindeksować FTP i wszystkie pliki rekurencyjnie.Ruby FTP Oddzielanie plików od folderów

Do tej pory starałem się ciągnąć w dół katalogu z

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 

Ale okazuje się, jeśli podzielić listę aż do ostatniego miejsca, nazwy plików i katalogów ze spacjami są pobierane źle. Potrzebujesz trochę pomocy w logice tutaj.

Odpowiedz

2

Możesz również użyć wyrażenia regularnego. Połączyłem jeden. Sprawdź, czy to działa, jak również nie wiem, czy Twój katalog wygląda inaczej. Musisz użyć Ruby 1.9 btw.

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) 

Jesteś w stanie uzyskać dostęp do elementów wg nazwy następnie

match[:type] zawiera 'd' jeśli jest to katalog, przestrzeni, czy jest to plik.

Wszystkie inne elementy również tam są. Co najważniejsze: match[:path].

+0

Możesz również użyć 'entry [1 ..- 1] .split [5] [13 ..- 1]', aby uzyskać ścieżkę i 'entry [0]', aby uzyskać typ –

+0

Czy to wyrażenie regularne działa dla wszystkich przypadki? Istnieje ogromna różnorodność serwerów FTP. Mamy klientów, którzy używają mało znanych, opartych na Windowsach serwerów, a zwracana przez nich lista plików wygląda zupełnie inaczej niż wersje Linuksa. Więc to, co zrobiłem, to dla każdego wpisu do pliku/katalogu wypróbowałem w nim CD, a jeśli to nie działa - rozważ to jako plik :) Działa jak urok. –

4

Można uniknąć rekursji jeśli lista wszystkich plików naraz

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

katalogi nie są ujęte w wykazie, lecz pełna ścieżka FTP jest nadal dostępny w nazwie.

EDIT

jestem przy założeniu, że każda nazwa pliku zawiera kropkę i katalogów nazwy nie. Dzięki za wzmiankę o @Niklas B.

+0

Próbuje teraz wprowadzić w życie głębszą rekursję, dzięki. – Norris

+1

Myślę, że to co najmniej zakłada, że ​​każdy plik ma kropkę w nim. Nie jestem pewien, czy to drugie założenie, że katalogi * nie * zawierają kropki w nich. Tak czy inaczej, uważam, że tekst powinien przynajmniej wspomnieć o tym fakcie. –

2

Istnieje wiele różnych serwerów FTP.

Mamy klientów, którzy korzystają z mało znanych firmowych serwerów Windows, a zwracana przez nich lista plików wygląda zupełnie inaczej niż wersje systemu Linux.

Więc co skończyło się robi jest dla każdego wpisu pliku/katalogu I spróbuj zmienić katalog do niego, a jeśli to nie zadziała - rozważyć to plik :)

następującą metodę „kuloodporne”:

# 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)} 

działa jak czar, ale Uwaga: jeśli katalog FTP ma mnóstwo w nim plików - metoda zajmuje natomiast przemierzać wszystkie z nich.

2

Zakładając, że serwer FTP zwraca listę plików podobnych do systemu Unix, takich jak, działa następujący kod. Przynajmniej dla mnie.

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] zawiera nazwę katalogu (zważywszy, że kontrolowana linia faktycznie przedstawia katalog).

0

Jak zaznaczył @Alex, używanie w nazwach plików wzorców nie jest niezawodne. Katalogi mogą mieć kropki w swoich nazwach (na przykład .ssh), a wykazy mogą się bardzo różnić na różnych serwerach.

Jego metoda działa, ale jak sam podkreśla, zajmuje to zbyt długo. Wolę używać metody .size z Net :: FTP. Powoduje zwrócenie rozmiaru pliku lub zgłasza błąd, jeśli plik jest katalogiem.

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