使用Paramiko SFTP复制目录

时间:2017-09-01 18:14:02

标签: python-3.x sftp rsync paramiko

我想模仿着名的Linux rsync命令的行为,如果在目录的末尾没有指定“/”并且在“test /”中复制了所有内容,它会从“test”复制整个目录。 “/“ 存在。我的本地“test”文件夹是这样的结构:

test
.
├── fileA.txt
├── fileB.txt
├── test1
│   └── test3
│       └── file3.txt
└── test2
    └── file2.txt

将整个本地测试文件夹复制到rsync中的远程服务器:

rsync -avzP test username@remotehost:/home/

在remotehost的主目录中将是

home
.
|__ test
    ├── fileA.txt
    ├── fileB.txt
    ├── test1
    │   └── test3
    │       └── file3.txt
    └── test2
        └── file2.txt

示例A

要复制本地“test”文件夹中的所有内容,不包括本身:

rsync -avzP test/ username@remotehost:/home/

主目录的结构将是:

home/
.
├── fileA.txt
├── fileB.txt
├── test1
│   └── test3
│       └── file3.txt
└── test2
    └── file2.txt

示例B

我所拥有的代码不适用于示例B.我考虑拆分路径并摆脱“测试”然后复制其中的所有内容但它只会引导我进入无限的,嵌套的for循环。另一个想法是使用os.listdir。如果是目录,请再次列出目录并复制该目录中的内容。这仍然是循环的另一个循环。上面的树结构是一个简单的例子,但在现实生活中,我们都知道目录可能是5级深度。我该如何实现例B?

def put (self, localpath, remotepath):

        sftp = self.ssh.open_sftp ()

        # Create remote directory if it doesn't exist
        try:
            sftp.stat (remotepath)
        except FileNotFoundError:
            sftp.mkdir (remotepath)

        if os.path.isfile (localpath):
            # Obtain file name from local path & append to remote path
            path = os.path.split (localpath)        # Returns a tuple (directory, filename)
            remote_filename = os.path.join (remotepath, path [1])
            print ('  Copying %s' % remote_filename)
            sftp.put (localpath, remote_filename)

        elif os.path.isdir (localpath):
            p = os.path.join (remotepath, localpath)
            try:
                sftp.stat (p)
            except FileNotFoundError:
                sftp.mkdir (p)

            for dirpath, dirnames, filenames in os.walk (localpath):
                # Traverse into each child directory and create sub directory if it doesn't exist
                if dirnames:
                    for dirname in dirnames:
                        subdir = os.path.join (dirpath, dirname)
                        try:
                            sftp.stat (subdir)
                        except FileNotFoundError:
                            sftp.mkdir (subdir)

                for filename in filenames:
                    local_filename = os.path.join (dirpath, filename)
                    remote_filename = os.path.join (remotepath, local_filename)
                    sftp.put (local_filename, remote_filename)

1 个答案:

答案 0 :(得分:0)

我明白了。它不是最漂亮但功能性的。如果有人有更好,更清洁,更pythonic的方式,请分享。

def put (self, localpath, remotepath):

    sftp = self.ssh.open_sftp ()

    # Create remote directory if it doesn't exist
    try:
        sftp.stat (remotepath)
    except FileNotFoundError:
        sftp.mkdir (remotepath)

    if os.path.isfile (localpath):
        # Obtain file name from local path & append to remote path
        path = os.path.split (localpath)        # Returns a tuple (directory, filename)
        remote_filename = os.path.join (remotepath, path [1])
        print ('  Copying %s' % remote_filename)
        sftp.put (localpath, remote_filename)

    elif os.path.isdir (localpath):
        if localpath.endswith ('/'):
            for dirpath, dirnames, filenames in os.walk (localpath):
                # Change local dirpath to match remote path. Ex: local/dir/.. to remote/dir/...
                remotedir = dirpath.split ('/')             # remotedir = [local, dir1, dir2, ...]
                remotedir [0] = remotepath.rstrip ('/')     # remotedir = [/remote, dir1, dir2, ...]
                remotedir = '/'.join (remotedir)

                # Traverse into each child directory and create sub directory if it doesn't exist on remote host
                if dirnames:
                    for dirname in dirnames:
                        subdir = os.path.join (remotedir, dirname)

                        try:
                            sftp.stat (subdir)
                        except FileNotFoundError:
                            sftp.mkdir (subdir)

                for filename in filenames:
                    localdir = os.path.join (dirpath, filename)
                    remotefile = os.path.join (remotedir, filename)
                    print ('  Copying %s' % localdir)
                    sftp.put (localdir, remotefile)
        else:
            # Create path /remote/local/dir1...
            p = os.path.join (remotepath, localpath)

            try:
                sftp.stat (p)
            except FileNotFoundError:
                sftp.mkdir (p)

            for dirpath, dirnames, filenames in os.walk (localpath):
                if dirnames:
                    for dirname in dirnames:
                        subdir = os.path.join (dirpath, dirname)
                        remotedir = os.path.join (remotepath, subdir)

                        try:
                            sftp.stat (remotedir)
                        except FileNotFoundError:
                            sftp.mkdir (remotedir)

                for filename in filenames:
                    local_filename = os.path.join (dirpath, filename)
                    remote_filename = os.path.join (remotepath, local_filename)
                    print (' Copying %s' % local_filename)
                    sftp.put (local_filename, remote_filename)
    else:
        print ('File or directory not found.')

结束结果:

示例A:

>>> ssh.put ('test', '/home/user/')
 Copying test/fileA.txt
 Copying test/fileB.txt
 Copying test/test1/test3/file3.txt
 Copying test/test2/file2.txt
Completed!

-sh-4.1$ ls -lh test/*
-rw-r----- 1 user users    0 Sep  1 23:43 test/fileA.txt
-rw-r----- 1 user users    0 Sep  1 23:43 test/fileB.txt

test/test1:
total 4.0K
drwxr-x--- 2 user users 4.0K Sep  1 23:43 test3

test/test2:
total 0
-rw-r----- 1 user users 0 Sep  1 23:43 file2.txt

-sh-4.1$ ls -lh test/*/*
-rw-r----- 1 user users    0 Sep  1 23:43 test/test2/file2.txt

test/test1/test3:
total 0
-rw-r----- 1 user users 0 Sep  1 23:43 file3.txt
-sh-4.1$ 

例B:

>>> ssh.put ('test/', '/home/user/')
  Copying test/fileA.txt
  Copying test/fileB.txt
  Copying test/test1/test3/file3.txt
  Copying test/test2/file2.txt
Completed!

-sh-4.1$ pwd
/home/user
-sh-4.1$ ls -lh
total 108K
-rw-r----- 1 user users    0 Sep  1 23:43 fileA.txt
-rw-r----- 1 user users    0 Sep  1 23:43 fileB.txt
drwxr-x--- 3 user users 4.0K Sep  1 23:43 test1
drwxr-x--- 2 user users 4.0K Sep  1 23:43 test2

-sh-4.1$ ls -lh test1 test2
test1:
total 4.0K
drwxr-x--- 2 user users 4.0K Sep  1 23:43 test3

test2:
total 0
-rw-r----- 1 user users 0 Sep  1 23:43 file2.txt

-sh-4.1$ ls -lh test1/test3/
total 0
-rw-r----- 1 user users 0 Sep  1 23:43 file3.txt
-sh-4.1$