web-dev-qa-db-ja.com

paramikoでのディレクトリ転送

Paramikoを使用してディレクトリ全体を転送するにはどうすればよいですか?私は使用しようとしています:

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

これは私にこのエラーを与えています-

Error : [Errno 21] Is a directory
25
fixxxer

これは、ローカルでpythonを使用する場合と同じように行う必要があります(シャットダウンを使用していない場合)。

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

6
JimB

Paramiko.SFTPClientをサブクラス化して、それに次のメソッドを追加できます。

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

それを使用するには:

transport = paramiko.Transport((Host, PORT))
transport.connect(username=USERNAME, password=PASSWORD)
sftp = MySFTPClient.from_transport(transport)
sftp.mkdir(target_path, ignore_existing=True)
sftp.put_dir(source_path, target_path)
sftp.close()
19
skoll

これが私のコードです:

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_files(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
6

sftp = self.client.open_sftp()をparamikoのものに置き換えて、ここでlibcloudを取り除くことができます。

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)
4
Andrey Gerzhov

このようなことをする私のために働き、すべてのフォルダとファイルがリモートサーバーにコピーされます。

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))
3
Zaffalon

これはすべてparamikoを使用して非常に簡単に行うことができます。

以下のコードの概要は次のとおりです:
-SFTPに接続します(ステップ1から3)
-ソースとターゲットのフォルダーを指定します。 (ステップ4)
-好きなところに1つずつコピーします(/ tmp /に送信しました)。 (ステップ5)

import paramiko

# 1 - Open a transport
Host="your-Host-name"
port = port_number
transport = paramiko.Transport((Host, port))

# 2 - Auth
password="sftp_password"
username="sftp_username"
transport.connect(username = username, password = password)

# 3 - Go!

sftp = paramiko.SFTPClient.from_transport(transport)

# 4 - Specify your source and target folders.
source_folder="some/folder/path/on/sftp"
inbound_files=sftp.listdir(source_folder)

# 5 - Download all files from that path
for file in inbound_files :
    filepath = source_folde+file
    localpath = "/tmp/"+file
    sftp.get(filepath, localpath)
2

そんなことはできないと思います。 os.walkのドキュメントを調べ、各ファイルを「手動」でコピーします。

2
Martijn

これが私の最初のStackOverflow回答です。今日はこれに似た仕事をしました。だから、私はpython and paramikoを使用してWindowsからLinuxにフォルダ全体をコピーする直接的な方法を見つけようとしました。少し調査した後、サブフォルダを持つ小さなサイズのフォルダで機能するこのソリューションを思いつきましたとその中のファイル。

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

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')
0
Raj401

私の知る限り、Paramikoは再帰的なファイルのアップロードをサポートしていません。しかし、私は ここでParamikoを使用した再帰的アップロードのソリューション を見つけました。再帰的なアップロード機能の抜粋に従います:

   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
Martin Kosek