使用Paramiko通过Python和Pythonista上传SFTP。无法创建目录/子目录

时间:2013-08-04 21:35:30

标签: python sftp paramiko mkdir pythonista

我正在尝试将图片上传到远程服务器上的uploads文件夹。文件夹结构始终为uploads/year/month/,我无法让paramiko检查文件夹是否存在,如果没有,请执行。

SSH连接正常,上传文件也正常,但在uploads目录中创建子文件夹不起作用。

我遇到了解决方案here。这与我的问题相同,我在iOS上使用Pythonista。选项A:我的代码是完全错误的,或者选项B是iOS / Pythonista特定的问题。

因此,来自另一个线程(上面链接)的代码设置一个定义并运行一个try / error循环来测试通过它的文件夹是否已经存在,如果没有创建它们。在我的脚本下面是# Set Definition for "mkdir -p"

使用remoteFilePath ...

进行调用
  1. 不必要因为:理想情况下它应该只测试datePath是否存在,因为remotePath肯定存在
  2. 可能有问题,因为: fileName没有路径,将被下一个命令放在那里。
  3. 我尝试调整脚本,但不知怎的,我无法使其工作。

    无论我尝试什么,我都会收到错误:

    • 版本1:TypeError: mkdir_p() takes exactly 2 arguments (1 given)"
    • 版本2:AttributeError: 'tulpe' object has no attribute 'rfind'
    • 版本3:Exception: unknown type for (/home/userZ/Dropbox/uploads/year/month', 'test.png') type <type 'tuple'>

    以下是脚本相关部分的摘要(如果您喜欢它的外观,则为gist):

    # Set Variables
    fileName = "temp.png"
    remotePath = "/home/userZ/Dropbox/uploads/"
    datePath = "year/month/"
    remoteFilePath =  remotePath + datePath + fileName #
    
    # Set Definition for "mkdir -p"
    def mkdir_p(sftp,remote_directory):
        remote_dirname, basename = os.path.split(remote_directory)
        mkdir_p(os.path.dirname(remote_directory))
        try:
            sftp.chdir(name)
        except IOError:
            sftp.mkdir(name)
            sftp.chdir(name)
    
    try:
        transport.connect(username = username, password = password)
        sftp = paramiko.SFTPClient.from_transport(transport)     # Start SFTP client
    
        # Try to make remote path - 3 Versions and all fail
        mkdir_p(sftp,remoteFilePath) # Version 1
        #mkdir_p(sftp, os.path.split(remoteFilePath)) # Version 2
        #sftp.mkdir(os.path.split(remoteFilePath)) # Version 3
    
        # Put file to remote
        sftp.put('temp.png', remoteFilePath)
    
        # Close connection
        finally:
            transport.close()
            sftp.close()
    

    感谢任何帮助。 (小心:OP = Python noob)。我依靠Paramiko,因为我的共享主机只支持SFTP。否则我会使用FTPlib。

5 个答案:

答案 0 :(得分:1)

你遇到了与FTP相同的问题,你不能mkdir / some / long / path,你必须

cd /
mkdir some # ignore errors if it exists
cd some
mkdir long # ignore errors if it exists
cd  long
mkdir path # ignore errors if it exists
cd path

我猜这个模型的历史原因是为客户端发出的任何命令提供一个简单的布尔SUCCEED / FAIL。

出现一些模糊错误,例如'无法创建目录 / some / long / path ,因为目录 / some / long 不存在'将会很痛苦在客户端处理的屁股。

在查看SFTP协议规范:文件名(http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#page-15)时,我不清楚客户是否希望在制作目录的上下文中理解'/'作为路径分隔符 - 因为您可以拥有一个窗口盒上的SFTP服务器,paramiko可能只是完全忽略对此的支持?

tl; dr:修改你的代码以将路径分成它的各个组件,尝试对它们进行chdir,如果失败,尝试制作它们,如果失败你就死了,否则chdir到下一个子目录,继续,直到您没有更多的子目录来创建。

修改

您对该行所遇到的具体问题

mkdir_p(os.path.split(remoteFilePath))

可以通过将其更改为

来修复
mkdir_p(sftp, os.path.split(remoteFilePath))

答案 1 :(得分:1)

CClauss得到了答案并将其放在上面链接的要点的评论部分。我不相信。

这是他的答案 - 因为其他人试图用paramiko模仿mkdir -p,然后你就去了:

  

我的感觉是你需要:尝试使用mkdir:/ home /尝试使用mkdir   :/ home / userZ /尝试mkdir on:/ home / userZ / Dropbox /尝试mkdir on   :/ home / userZ / Dropbox / uploads /尝试使用mkdir   :/ home / userZ / Dropbox / uploads / year /尝试使用mkdir   :/ home / userZ / Dropbox / uploads / year / month /然后cd到   / home / userZ / Dropbox / uploads / year / month /然后复制文件

     

试试这个......

# Slash '/' is hardcoded because ftp always uses slash
def mk_each_dir(sftp, inRemoteDir):
    currentDir = '/'
    for dirElement in inRemoteDir.split('/'):
        if dirElement:
            currentDir += dirElement + '/'
            print('Try to mkdir on :' + currentDir)
            try:
                sftp.mkdir(currentDir)
            except:
                pass # fail silently if remote directory already exists

# Set Variables
fileName = "temp.png"
remotePath = "/home/userZ/Dropbox/uploads/"
datePath = "year/month/"
remoteDirPath =  remotePath + datePath
mk_each_dir(sftp, remoteDirPath)
sftp.chdir(remoteDirPath)
remoteFilePath =  remoteDirPath + fileName

答案 2 :(得分:1)

import os

def mkpath(path, sftp):
    """mkdir -p helper for paramiko

    Args:
        path: string of path to create
        sftp: paramiko sftp client
    """
    path = os.path.dirname(path)
    if len(path) > 1:
        try:
            sftp.mkdir(path)
        except IOError:
            mkpath(path, sftp)

这样的事情为我解决了问题。在完整mkpath参数上执行sftp.put之前,我会调用remotepath

*我的问题是sftp.mkdir无法以递归方式创建目录。

答案 3 :(得分:0)

是的,下面的内容为您提供了诀窍。这就是我几年来一直在使用的东西。就像Cclaus所说,你需要在尝试创建子目录之前创建每个路径。 createPath()只需要你需要的魔力。

def ftpWrite(sftpConn, localpath, remotepath):
    createPath(sftpConn, remotepath)
    sftpConn.put(localpath, remotepath)

def createPath(sftpConn, remotepath):
    parts = remotepath.split('/')
    for n in range(3, len(parts)):
        path = '/'.join(parts[:n])       
        try:
            sftpConn.stat(path)
        except:
            sftpConn.mkdir(path)  

答案 4 :(得分:0)

用于在某些文件夹不存在时创建子文件夹链的功能(通过Paramiko SFTP Connection对象)

def folder_creator(path):

    paramiko_ssh = paramiko.SSHClient()
    # additional paramiko manipulations if required here
    paramiko_sftp = paramiko_ssh.open_sftp()

    path_parts = path.split('/')
    first_dir = '/'.join(path_parts[0:2])
    all_parts = [first_dir] + path_parts[2:]

    for dir in all_parts:
            try:
                    paramiko_sftp.chdir(dir)
            except IOError:
                    paramiko_sftp.mkdir(dir)
                    paramiko_sftp.chdir(dir)

    paramiko_ssh.close()