2

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

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

我在这里遇到了看起来像解决方案的东西。我有同样的问题,我在 iOS 上并使用 Pythonista。选项 A:我的代码完全错误,或者选项 B 是 iOS/Pythonista 特有的问题。

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

remoteFilePath用…调用它

  1. 不必要的,因为:理想情况下,它应该只测试是否datePath存在,因为remotePath肯定存在
  2. 可能有问题,因为: fileName没有路径,将由下一个命令放在那里。

我尝试调整脚本,但不知何故我无法使其工作。

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

  • 使用版本 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'>

这是脚本相关部分的片段(如果您更喜欢它的外观,也可以是要点):

# 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。

4

5 回答 5

1

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

这是他的回答——因为其他人都试图mkdir -p用 paramiko 效仿,那么你就去吧:

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

尝试这个...

# 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
于 2013-08-06T17:23:47.397 回答
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 协议规范:文件名(https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#page-15)时,我不清楚客户是否应该理解'/' 作为创建目录的上下文中的路径分隔符 - 因为您也可以在 Windows 机器上拥有一个 SFTP 服务器,paramiko 可能会完全忽略对此的支持?

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

编辑

您遇到的具体问题

mkdir_p(os.path.split(remoteFilePath))

可以通过将其更改为来修复

mkdir_p(sftp, os.path.split(remoteFilePath))
于 2013-08-04T22:32:37.367 回答
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不能递归地创建目录。

于 2017-06-09T21:08:42.900 回答
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)  
于 2013-09-13T19:36:19.883 回答
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()
于 2018-10-16T09:06:14.087 回答