2012-03-04 36 views
6

私はFTPをクロールしてすべてのファイルを再帰的にプルダウンしようとしています。私はRuby 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 

でディレクトリをプルダウンしようとしている。しかし、あなたが最後のスペースまでリストを分割した場合には、判明した今まで

、スペースを含むファイル名やディレクトリはフェッチ間違っています。 ここでロジックについて少し助けが必要です。

答えて

2

正規表現を使用することもできます。私は一緒に1つを入れます。それがあなたのために働くかどうかを確認してください。 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) 

match[:type]それはディレクトリだ場合、それは、ファイルの場合は、スペースを'd'が含まれています。

他のすべての要素も同様に存在します。最も重要なのはmatch[:path]です。

+0

パスを取得するために 'entry [1 ..- 1] .split [5] [13. .. 1]'を使うこともできます –

+0

この正規表現はすべてのケース? FTPサーバーは多種多様です。私たちには、あまり知られていない独自のWindowsベースのサーバーを使用するクライアントがあり、それらから返されるファイルのリストはLinuxのバージョンとはまったく異なります。だから、私がやったことは、各ファイル/ディレクトリのエントリにCDを試してみると、これがうまくいかない場合です - それをファイルと見なします:) 魅力のように動作します。 –

4

一度

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

ディレクトリがリストに含まれていませんが、完全なFTPパスは、名前でまだ使用可能である時にすべてのファイルを一覧表示する場合は、再帰を避けることができます。私はそれぞれのファイル名が含まれていることを仮定してい

EDIT

ドットとディレクトリ名にはありません。 @Niklas B.に感謝します。

+0

今、より深い再帰で彼を実装しようとしています、ありがとう。 – Norris

+1

これは少なくとも、すべてのファイルにドットが入っていることを前提としています。私はディレクトリがドットを持たないという第二の仮定を立てているかどうかはわかりません。いずれにせよ、私はそのテキストが少なくともその事実を言及すべきだと思う。 –

2

膨大な種類の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

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]

は(検査ラインが実際にディレクトリを表すと仮定)ディレクトリの名前を含みます。

0

@Alexが指摘しているように、ファイル名にパターンを使用することはほとんど信頼できません。ディレクトリには名前にドットを付けることができます(例:.ssh)。異なるサーバーではリストが非常に異なる場合があります。

彼の方法は機能しますが、彼自身が指摘しているように、時間がかかりすぎます。 Net :: FTPの.sizeメソッドを使用することをお勧めします。 ファイルのサイズを返します。ファイルがディレクトリの場合はエラーをスローします。

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 
関連する問題