使用Paramiko通过Python和Pythonista上传SFTP。Can';t创建目录/子目录

使用Paramiko通过Python和Pythonista上传SFTP。Can';t创建目录/子目录,python,sftp,paramiko,mkdir,pythonista,Python,Sftp,Paramiko,Mkdir,Pythonista,我正在尝试将图像上载到远程服务器上的上载文件夹。文件夹结构总是uploads/year/month/,我无法让paramiko检查文件夹是否存在,如果不存在,就创建它们 SSH连接正在工作,上载文件也在工作,但在uploads目录中创建子文件夹不起作用 我遇到了解决方案。这和我的问题一样,但我在iOS上使用Python。选项A:我的代码是完全错误的,或者选项B是iOS/Pythonista特定的问题 因此,来自另一个线程(上面链接的)的代码设置了一个定义,并运行一个try/error循环来测试通

我正在尝试将图像上载到远程服务器上的上载文件夹。文件夹结构总是
uploads/year/month/
,我无法让paramiko检查文件夹是否存在,如果不存在,就创建它们

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

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

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

使用
远程文件路径调用它

  • 不必要,因为:理想情况下,它应该只测试
    datePath
    是否存在,因为
    remotePath
    肯定存在
  • 可能有问题,因为:
    fileName
    没有路径,将由下一个命令放在那里
  • 我试着调整脚本,但不知怎的,我无法让它工作

    无论我尝试什么,我都会出错:
    • 对于版本1:
      TypeError:mkdir\u p()正好接受2个参数(给定1个)“
    • 对于版本2:
      AttributeError:“tulpe”对象没有属性“rfind”
    • 对于第3版:
      异常:(/home/userZ/Dropbox/uploads/year/month、'test.png')类型的未知类型
    下面是脚本相关部分的一个片段(如果您喜欢它的外观,也可以是一个示例):


    非常感谢您的帮助。(小心:OP=Python noob)。我依赖Paramiko,因为我的共享主机只支持SFTP。否则我会选择FTPlib。

    您在使用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
    
    我猜这个模型的历史原因是为客户机发出的任何命令提供一个简单的布尔值success/FAIL

    如果出现一些模糊错误,例如“由于目录/some/long不存在,所以无法生成目录/some/long/path”,那么在客户端处理这些错误将是一件痛苦的事情

    在查看SFTP协议规范re:filenames()时,我不清楚客户端是否希望在创建目录的上下文中将“/”理解为路径分隔符-因为您也可以在windows机箱上安装SFTP服务器,paramiko可能会完全忽略对这一点的支持

    修改您的代码,将路径拆分为各个组件,尝试chdir到它们,如果失败,尝试创建它们,如果失败,您就死了,否则chdir到下一个子目录并继续,直到您没有更多的子目录要创建

    编辑

    您在线路上遇到的具体问题

    mkdir_p(os.path.split(remoteFilePath))
    
    可以通过将其更改为

    mkdir_p(sftp, os.path.split(remoteFilePath))
    
    我得到了答案,并把它放在上面链接的要点的评论部分。我不相信

    这就是他的答案——因为其他人都试图模仿帕拉米科的
    mkdir-p
    ,那么你就来了:

    我的感觉是,您需要:尝试打开mkdir:/home/尝试打开mkdir :/home/userZ/Try to mkdir on:/home/userZ/Dropbox/Try to mkdir on :/home/userZ/Dropbox/uploads/尝试打开mkdir :/home/userZ/Dropbox/uploads/year/Try to mkdir on :/home/userZ/Dropbox/uploads/year/month/Then cd to /home/userZ/Dropbox/uploads/year/month/然后复制您的文件

    试试这个


    是的,像下面这样的东西可以帮到你。这就是我已经使用了几年的东西。就像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)  
    
    类似这样的操作为我解决了问题*。在执行
    sftp之前,我调用
    mkpath
    。将
    放在完整的
    remotepath
    参数上


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

    如果某些文件夹不存在,则创建子文件夹链的函数(通过Paramiko sftp连接对象)


    Mh.坦白说,我想我已经通过添加另一个线程的定义做到了这一点。我编辑了我的问题,以便更清楚地说明我错在哪里。更新了我的答案以解决您的问题。简单的语法错误。我尝试了这种方法,但得到了一个错误(请参阅上面的编辑-版本2):AttributeError:'tulpe'对象没有属性'rfind'///谢谢你的帮助,我今天一直在尝试,只是用一条湿毛巾裹住我的头以防止它冒出过多的蒸汽。我想我理解这个问题-分裂导致了这个问题。请尝试mkdir_p(sftp,os.path.split(remote_directory)),而不是mkdir_p(sftp,remote_dirname)。如果这还不能解决问题,请查看原始mkdir_p代码,并确保已正确剪切/粘贴。感谢您提供了一些附加信息和您的工作流程。我将对此进行研究。
    # 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
    
    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)  
    
    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)
    
    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()