如何使用paramiko传输完整目录? 我正在尝试使用:
sftp.put("/Folder1","/Folder2")
这给了我这个错误 -
Error : [Errno 21] Is a directory
答案 0 :(得分:13)
您可以继承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()
答案 1 :(得分:6)
这是我的代码:
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
答案 2 :(得分:5)
你需要这样做就像你在python本地一样(如果你没有使用shutils)。
将os.walk()
与sftp.mkdir()
和sftp.put()
结合使用。您可能还希望使用os.path.islink()
检查每个文件和目录,具体取决于您是否要解析符号链接。
答案 3 :(得分:4)
您可以将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 :(得分:3)
为我这样做,所有文件夹和文件都被复制到远程服务器。
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))
答案 5 :(得分:2)
我认为你不能那样做。查找os.walk
的文档并“手动”复制每个文件。
答案 6 :(得分: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
调用上述函数进行递归上传,也可以自行实现。
答案 7 :(得分:0)
这是我的第一个StackOverflow答案。我今天有一个类似于此的任务。所以,我试图找到一种直接的方法,使用python和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')
答案 8 :(得分:0)
使用paramiko可以很容易地完成所有操作。
以下代码的高级摘要是:
-连接到SFTP(步骤1至3)
-指定您的源文件夹和目标文件夹。 (步骤4)
-将它们一一复制到您喜欢的任何位置(我已将它们发送到/ 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)
答案 9 :(得分:0)
Paramiko本身不支持目录传输。正如许多现有答案所示,您必须实现它。
或者您可以使用pysftp。它是Paramiko的包装,具有更多类似Python的外观和感觉,并支持递归操作。见
或者您也可以将代码基于pysftp source code。完整的独立便携式Paramiko专用代码,请参阅我的答案:
正如上面我的回答所示,如果您在Windows上,则实际上必须使用自己的代码,因为pysftp无法在其中运行。
答案 10 :(得分:0)
我的答案与上面类似,只是列出一个清单,然后逐个转移。
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname='11.11.11.1111', username='root', password='********', port=22)
sftp_client = ssh.open_sftp()
source_folder = '/var/ftp/file_pass'
local_folder = 'C:/temp/file_pass'
inbound_files = sftp_client.listdir(source_folder)
print(inbound_files)
for ele in inbound_files:
try:
path_from = source_folder + '/' + ele
path_to = local_folder + '/'+ ele
sftp_client.get(path_from, path_to)
except:
print(ele)
sftp_client.close()
ssh.close()