2010-12-10 59 views
17

paramikoを使って完全なディレクトリをどのように転送しますか? 私が使用しようとしている:私は、このエラーを与えているparamikoのディレクトリ転送

sftp.put("/Folder1","/Folder2") 

- 私はあなたがそれを行うことができるとは思わない

Error : [Errno 21] Is a directory 

答えて

4

これは、シャットルを使用していなかった場合と同じように、ローカルでPythonを使用する場合と同様に行う必要があります。

os.walk()sftp.mkdir()sftp.put()を組み合わせてください。また、シンボリックリンクを解決するかどうかによって、各ファイルとディレクトリをで確認することもできます。

2

を。 os.walkのドキュメントを参照し、各ファイルを「手動で」コピーします。

0

私が知る限り、Paramikoは再帰的ファイルアップロードをサポートしていません。しかし、私はsolution for recursive upload using Paramiko hereを見つけました。その再帰アップロード機能の抜粋を次に示します。

def _send_recursive(self, files): 
     for base in files: 
      lastdir = base 
      for root, dirs, fls in os.walk(base): 
       # pop back out to the next dir in the walk 
       while lastdir != os.path.commonprefix([lastdir, root]): 
        self._send_popd() 
        lastdir = os.path.split(lastdir)[0] 
       self._send_pushd(root) 
       lastdir = root 
       self._send_files([os.path.join(root, f) for f in fls]) 

あなたがしようといずれかの再帰的なアップロードのため上記の関数を呼び出すその機能SCPClient.putを使用するか、自分でそれを実装することができます。

+0

os.walk()はこの問題を解決する正しい方法ですが、SCP固有の方法で処理するため、これを正確にコピーしないでください。 SFTPは少し違った働きをしています(免責事項、私はそのコードを書いています) – JimB

+0

@Martin Kosek - あなたの答えは気に入っていますが、解決策へのリンクが壊れているようです。編集して修正できますか?ありがとう。 – RobertMS

+0

@RobertMS - そうですね、私はPythonモジュールが削除されたのを見ています。この場合、私はJimBのソリューションがos.walk()、sftp.mkdir()、sftp.put()のベスト・コンビネーションになると思います。 –

3

sftp = self.client.open_sftp()をparamikoのものに置き換えて、ここでlibcloudを取り除くことができます。あなたはparamiko.SFTPClientをサブクラス化し、それに次のメソッドを追加することができます

import os.path 
from stat import S_ISDIR 
from libcloud.compute.ssh import SSHClient 
from paramiko.sftp import SFTPError 

class CloudSSHClient(SSHClient): 


    @staticmethod 
    def normalize_dirpath(dirpath): 
     while dirpath.endswith("/"): 
      dirpath = dirpath[:-1] 
     return dirpath 


    def mkdir(self, sftp, remotepath, mode=0777, intermediate=False): 
     remotepath = self.normalize_dirpath(remotepath) 
     if intermediate: 
      try: 
       sftp.mkdir(remotepath, mode=mode) 
      except IOError, e: 
       self.mkdir(sftp, remotepath.rsplit("/", 1)[0], mode=mode, 
          intermediate=True) 
       return sftp.mkdir(remotepath, mode=mode) 
     else: 
      sftp.mkdir(remotepath, mode=mode) 


    def put_dir_recursively(self, localpath, remotepath, preserve_perm=True): 
     "upload local directory to remote recursively" 

     assert remotepath.startswith("/"), "%s must be absolute path" % remotepath 

     # normalize 
     localpath = self.normalize_dirpath(localpath) 
     remotepath = self.normalize_dirpath(remotepath) 

     sftp = self.client.open_sftp() 

     try: 
      sftp.chdir(remotepath) 
      localsuffix = localpath.rsplit("/", 1)[1] 
      remotesuffix = remotepath.rsplit("/", 1)[1] 
      if localsuffix != remotesuffix: 
       remotepath = os.path.join(remotepath, localsuffix) 
     except IOError, e: 
      pass 

     for root, dirs, fls in os.walk(localpath): 
      prefix = os.path.commonprefix([localpath, root]) 
      suffix = root.split(prefix, 1)[1] 
      if suffix.startswith("/"): 
       suffix = suffix[1:] 

      remroot = os.path.join(remotepath, suffix) 

      try: 
       sftp.chdir(remroot) 
      except IOError, e: 
       if preserve_perm: 
        mode = os.stat(root).st_mode & 0777 
       else: 
        mode = 0777 
       self.mkdir(sftp, remroot, mode=mode, intermediate=True) 
       sftp.chdir(remroot) 

      for f in fls: 
       remfile = os.path.join(remroot, f) 
       localfile = os.path.join(root, f) 
       sftp.put(localfile, remfile) 
       if preserve_perm: 
        sftp.chmod(remfile, os.stat(localfile).st_mode & 0777) 
+0

ニース、完全な答え。ちょっとした点: 'str.rsplit'の代わりに' os.path.split'を使うことをお勧めします。また、 'normalize_path'メソッドを定義しますが、' put_dir_recursively'では 'suffix = suffix [1:]'を実行します。 –

9

import paramiko 
import os 

class MySFTPClient(paramiko.SFTPClient): 
    def put_dir(self, source, target): 
     ''' Uploads the contents of the source directory to the target path. The 
      target directory needs to exists. All subdirectories in source are 
      created under target. 
     ''' 
     for item in os.listdir(source): 
      if os.path.isfile(os.path.join(source, item)): 
       self.put(os.path.join(source, item), '%s/%s' % (target, item)) 
      else: 
       self.mkdir('%s/%s' % (target, item), ignore_existing=True) 
       self.put_dir(os.path.join(source, item), '%s/%s' % (target, item)) 

    def mkdir(self, path, mode=511, ignore_existing=False): 
     ''' Augments mkdir by adding an option to not fail if the folder exists ''' 
     try: 
      super(MySFTPClient, self).mkdir(path, mode) 
     except IOError: 
      if ignore_existing: 
       pass 
      else: 
       raise 
2

作品私はこのような何かを行うため、すべてのフォルダとファイルがリモートサーバにコピーされます。ここで

parent = os.path.expanduser("~") 
for dirpath, dirnames, filenames in os.walk(parent): 
    remote_path = os.path.join(remote_location, dirpath[len(parent)+1:]) 
     try: 
      ftp.listdir(remote_path) 
     except IOError: 
      ftp.mkdir(remote_path) 

     for filename in filenames: 
      ftp.put(os.path.join(dirpath, filename), os.path.join(remote_path, filename)) 
2

はコードの私の作品です:

import errno 
import os 
import stat 

def download_files(sftp_client, remote_dir, local_dir): 
    if not exists_remote(sftp_client, remote_dir): 
     return 

    if not os.path.exists(local_dir): 
     os.mkdir(local_dir) 

    for filename in sftp_client.listdir(remote_dir): 
     if stat.S_ISDIR(sftp_client.stat(remote_dir + filename).st_mode): 
      # uses '/' path delimiter for remote server 
      download_file(sftp_client, remote_dir + filename + '/', os.path.join(local_dir, filename)) 
     else: 
      if not os.path.isfile(os.path.join(local_dir, filename)): 
       sftp_client.get(remote_dir + filename, os.path.join(local_dir, filename)) 


def exists_remote(sftp_client, path): 
    try: 
     sftp_client.stat(path) 
    except IOError, e: 
     if e.errno == errno.ENOENT: 
      return False 
     raise 
    else: 
     return True 
0

これが私の最初のStackOverflowの答えです。私は今日これに似た仕事をしていました。ですから、私はPythonとparamikoを使ってWindowsからLinuxにフォルダ全体をコピーする直接的な方法を見つけようとしました。ちょっとした調査の後、サブフォルダとファイルを含む小さなサイズのフォルダで動作するこのソリューションを思いつきました。

このソリューションは、まず現在のフォルダ(ここではos.walk()が役に立ちます)のzipファイルを作成してから、コピー先のサーバにコピーして解凍します。

zipHere = zipfile.ZipFile("file_to_copy.zip", "w") 

for root, folders, files in os.walk(FILE_TO_COPY_PATH): 
    for file in files: 
     zipHere.write(os.path.join(root, file), arcname=os.path.join(os.path.relpath(root, os.path.dirname(FILE_TO_COPY_PATH)), file)) 
    for folder in folders: 
     zipHere.write(os.path.join(root, folder), arcname=os.path.join(os.path.relpath(root, os.path.dirname(FILE_TO_COPY_PATH)), folder)) 
zipHere.close() 

# sftp is the paramiko.SFTPClient connection 
sftp.put('local_zip_file_location','remote_zip_file_location') 

# telnet_conn is the telnetlib.Telnet connection 
telnet_conn.write('cd cd_to_zip_file_location') 
telnet_conn.write('unzip -o file_to_copy.zip') 
関連する問題