2013-02-11 31 views
15

Tôi muốn tải tệp lên máy chủ từ xa bằng Python. Tôi muốn kiểm tra trước nếu con đường từ xa thực sự tồn tại, và nếu nó không phải là, để tạo ra nó. Trong mã giả:Tải tệp lên bằng SFTP bằng Python, nhưng tạo thư mục nếu đường dẫn không tồn tại

if(remote_path not exist): 
    create_path(remote_path) 
upload_file(local_file, remote_path) 

Tôi đã suy nghĩ về việc thực hiện lệnh trong Paramiko để tạo đường dẫn (ví dụ: mkdir -p remote_path). Tôi đến với điều này:

# I didn't test this code 

import paramiko, sys 

ssh = paramiko.SSHClient() 
ssh.connect(myhost, 22, myusername, mypassword) 
ssh.exec_command('mkdir -p ' + remote_path) 
ssh.close 

transport = paramiko.Transport((myhost, 22)) 
transport.connect(username = myusername, password = mypassword) 

sftp = paramiko.SFTPClient.from_transport(transport) 
sftp.put(local_path, remote_path) 
sftp.close() 

transport.close() 

Nhưng giải pháp này không có âm thanh tốt với tôi, vì tôi đóng kết nối và sau đó mở lại nó một lần nữa. Có cách nào tốt hơn để làm điều đó không?

+0

liên quan: [os.renames for ftp in python] (http://stackoverflow.com/q/14641267/4279) – jfs

Trả lời

26

SFTP hỗ trợ các lệnh FTP thông thường (chdir, mkdir, vv ...), do đó sử dụng những:

sftp = paramiko.SFTPClient.from_transport(transport) 
try: 
    sftp.chdir(remote_path) # Test if remote_path exists 
except IOError: 
    sftp.mkdir(remote_path) # Create remote_path 
    sftp.chdir(remote_path) 
sftp.put(local_path, '.') # At this point, you are in remote_path in either case 
sftp.close() 

Để mô phỏng đầy đủ mkdir -p, bạn có thể làm việc thông qua remote_path đệ quy:

import os.path 

def mkdir_p(sftp, remote_directory): 
    """Change to this directory, recursively making new folders if needed. 
    Returns True if any folders were created.""" 
    if remote_directory == '/': 
     # absolute path so change directory to root 
     sftp.chdir('/') 
     return 
    if remote_directory == '': 
     # top-level relative directory must exist 
     return 
    try: 
     sftp.chdir(remote_directory) # sub-directory exists 
    except IOError: 
     dirname, basename = os.path.split(remote_directory.rstrip('/')) 
     mkdir_p(sftp, dirname) # make parent directories 
     sftp.mkdir(basename) # sub-directory missing, so created it 
     sftp.chdir(basename) 
     return True 

sftp = paramiko.SFTPClient.from_transport(transport) 
mkdir_p(sftp, remote_path) 
sftp.put(local_path, '.') # At this point, you are in remote_path 
sftp.close() 

Tất nhiên, nếu remote_path cũng chứa tên tệp từ xa thì nó cần phải được tách ra, thư mục được chuyển tới mkdir_p và tên tệp được sử dụng thay cho '.' trong sftp.put.

+0

nó không xử lý các thư mục cha không tồn tại ('-p'). So sánh os.mkdir() với os.makedirs(). Chia đường dẫn và thực hiện cuộc gọi đệ quy để tạo thư mục cha nếu cần thiết – jfs

+0

có, đã đồng ý, sẽ cập nhật tương ứng. – isedev

+0

trong chức năng mkdir_p không có xử lý để sftp – franzlorenzon

5

Something đơn giản và hơi dễ đọc hơn quá

def mkdir_p(sftp, remote, is_dir=False): 
    """ 
    emulates mkdir_p if required. 
    sftp - is a valid sftp object 
    remote - remote path to create. 
    """ 
    dirs_ = [] 
    if is_dir: 
     dir_ = remote 
    else: 
     dir_, basename = os.path.split(remote) 
    while len(dir_) > 1: 
     dirs_.append(dir_) 
     dir_, _ = os.path.split(dir_) 

    if len(dir_) == 1 and not dir_.startswith("/"): 
     dirs_.append(dir_) # For a remote path like y/x.txt 

    while len(dirs_): 
     dir_ = dirs_.pop() 
     try: 
      sftp.stat(dir_) 
     except: 
      print "making ... dir", dir_ 
      sftp.mkdir(dir_) 
+0

+1 để cung cấp giải pháp thay thế không đệ quy. Lưu ý rằng tham số đầu vào "từ xa" ở đây là một đường dẫn tệp từ xa.Thay vào đó, nếu bạn muốn hàm này có đường dẫn thư mục từ xa làm đầu vào, hãy thay thế "dir_, basename = os.path.split (remote)" bằng "dir_ = remote". –

+0

@AlanEvangelista Cảm ơn bạn đã bình luận. Đã cập nhật mã vượt qua cờ 'is_dir'. Vui lòng xem lại và chỉnh sửa nếu được yêu cầu. – gabhijit

1

Đã phải làm ngày hôm nay. Đây là cách tôi đã làm nó.

def mkdir_p(sftp, remote_directory): 
    dir_path = str() 
    for dir_folder in remote_directory.split("/"): 
     if dir_folder == "": 
      continue 
     dir_path += r"/{0}".format(dir_folder) 
     try: 
      sftp.listdir(dir_path) 
     except IOError: 
      sftp.mkdir(dir_path)