2012-03-04 41 views
6

Tôi đang cố gắng thu thập thông tin FTP và kéo xuống tất cả các tập tin đệ quy.Ruby FTP Tách tập tin từ các thư mục

Cho đến bây giờ tôi đã cố gắng để kéo xuống một thư mục với

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 

Nhưng hóa ra, nếu bạn chia danh sách lên cho đến khi không gian cuối cùng, tên tập tin và thư mục với các không gian là sai vời. Cần một chút trợ giúp về logic ở đây.

Trả lời

2

Bạn cũng có thể sử dụng cụm từ thông dụng. Tôi đặt một cái lại với nhau. Xin vui lòng xác minh nếu nó hoạt động cho bạn cũng như tôi không biết nó danh sách dir của bạn trông khác nhau. Bạn phải sử dụng 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) 

Bạn có thể truy cập vào các yếu tố theo tên sau đó

match[:type] chứa một 'd' nếu đó là một thư mục, một không gian nếu đó là một tập tin.

Tất cả các yếu tố khác đều có ở đó. Quan trọng nhất là match[:path].

+0

Bạn cũng có thể sử dụng 'mục [1 ..- 1] .split [5] [13 ..- 1]' để lấy đường dẫn và 'mục [0]' để lấy kiểu –

+0

Cụm từ thông dụng này có hoạt động cho tất cả các trường hợp? Có rất nhiều loại máy chủ FTP xung quanh. Chúng tôi có các khách hàng sử dụng một số máy chủ dựa trên cửa sổ độc quyền tối nghĩa và danh sách tệp được họ trả về trông hoàn toàn khác với các phiên bản Linux. Vì vậy, những gì tôi đã kết thúc làm là cho mỗi tập tin/mục nhập thư mục tôi thử CD vào nó và nếu điều này không làm việc - xem xét nó một tập tin :) Làm việc như một say mê. –

4

Bạn có thể tránh đệ quy nếu bạn liệt kê tất cả các file cùng một lúc

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

Thư mục không có trong danh sách, nhưng con đường ftp đầy đủ là vẫn có sẵn trong tên.

EDIT

Tôi giả định rằng mỗi tên tệp chứa dấu chấm và tên thư mục thì không. Cảm ơn bạn đã đề cập đến @Niklas B.

+0

Cố gắng triển khai thực hiện lời nhắc sâu sắc hơn ngay bây giờ, cảm ơn. – Norris

+1

Tôi nghĩ rằng điều này làm cho ít nhất là giả định rằng mỗi tập tin có một dấu chấm trong đó. Tôi không chắc liệu nó có làm giả định thứ hai rằng các thư mục * không * có dấu chấm trong chúng hay không. Dù bằng cách nào, tôi nghĩ rằng văn bản nên ít nhất là đề cập đến thực tế đó. –

2

Có rất nhiều máy chủ FTP xung quanh.

Chúng tôi có các khách hàng sử dụng một số máy chủ Windows độc quyền tối thiểu và danh sách tệp được họ trả lại trông hoàn toàn khác với các phiên bản Linux.

Vì vậy, những gì tôi đã kết thúc làm là dành cho mỗi mục tập tin/thư mục Tôi cố gắng thay đổi thư mục vào nó và nếu điều này không hoạt động - coi đó là một tập tin :)

Các phương pháp sau đây là "viên đạn bằng chứng":

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

trình như một say mê, nhưng xin lưu ý: nếu thư mục FTP có hàng tấn dữ liệu trong nó - phương pháp này mất một thời gian phải đi qua tất cả chúng.

2

Giả sử rằng máy chủ FTP trả về danh sách tệp giống như Unix, mã sau hoạt động. Ít nhất là cho tôi.

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] chứa tên của thư mục (cho biết dòng được kiểm tra thực sự đại diện cho thư mục).

0

Khi @Alex chỉ ra, việc sử dụng các mẫu trong tên tệp cho điều này là không đáng tin cậy. Thư mục CÓ THỂ có dấu chấm trong tên của chúng (ví dụ .ssh) và danh sách có thể rất khác nhau trên các máy chủ khác nhau.

Phương pháp của anh ấy hoạt động, nhưng như anh ta đã chỉ ra, mất quá nhiều thời gian. Tôi thích sử dụng phương thức .size từ Net :: FTP. Nó trả về kích thước của một tập tin, hoặc ném một lỗi nếu tập tin là một thư mục.

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 
Các vấn đề liên quan