使用pycurl从西里尔路径上传文件

1 投票
2 回答
1220 浏览
提问于 2025-04-16 11:15

我最近设计了一个上传对话框,使用的是PyCURL,这个对话框我在几个应用程序中都用到了。
我在设置pycurl的HTTPPOST选项时遇到了问题。我是这样设置的:
self.curl.setopt(self.curl.HTTPPOST, [(field, (self.curl.FORM_FILE, filename))])
如果filename是字符串,那一切都没问题。但是如果我传入的是unicode,就会出现类型错误(TypeError)。
有没有办法让我使用西里尔字母的路径呢?我尝试过用UTF-8编码,但没有成功。
谢谢你的时间。

更新:

其实我从WX控件中获取filename,所以在我处理之前它就是unicode格式。当我把它编码成UTF-8时(使用filename = filename.encode('UTF-8')),setopt设置是没问题的,但在执行时就出错了:

* About to connect() to example.com port 80 (#0)
*   Trying 123.123.123.123... * connected
* Connected to example.com (123.123.123.123) port 80 (#0)
* failed creating formpost data
* Connection #0 to host example.com left intact
Traceback (most recent call last):
  File "c:\python27\lib\site-packages\transfer_dialogs-0.28-py2.7.egg\transfer_dialogs\transfer_dialogs.py", line 64, in perform_transfer
    self.curl.perform()
error: (26, 'failed creating formpost data')

更新2:

根据要求,提供更多信息。filename包含的是从打开对话框中获取的GetValue()结果。
logging.debug("Filename: %r encoded filename: %r" % (filename, filename.encode('UTF-8')))
结果是:
Sat Feb 05, 2011 03:33:56 core.dialogs.upload_audio DEBUG: Filename: u'C:\Users\Q\test\\u0422\u0435\u0441\u0442\u043e\u0432\u0430\u044f \u043f\u0430\u043f\u043a\u0430\test.mp3' encoded filename: 'C:\Users\Q\test\\xd0\xa2\xd0\xb5\xd1\x81\xd1\x82\xd0\xbe\xd0\xb2\xd0\xb0\xd1\x8f \xd0\xbf\xd0\xb0\xd0\xbf\xd0\xba\xd0\xb0\test.mp3'

2 个回答

0

把这个问题分成两个部分来解决:

  1. 告诉pycurl要打开哪个文件来读取文件数据
  2. 把文件名以正确的编码发送到服务器

这两个编码可能相同,也可能不同。

对于第一部分,可以使用 sys.getfilesystemencoding() 来把你在Python代码中使用的Unicode文件名(这个文件名是正确的)转换成一个字符串,这样pycurl/libcurl就能用 fopen() 正确打开它。你可以使用 strace(在Linux上)或者相应的工具来检查pycurl是否打开了正确的文件路径,Windows和Mac上也有类似的工具。

如果这个方法完全失败,你还可以通过 pycurl.READFUNCTION 从Python直接传输文件数据流。

对于第二部分,了解文件上传时文件名是如何传输的,这里有个例子。我没有找到很好的链接,但我知道这个过程并不简单,特别是当文件名非常长的时候。

0

文件名应该使用UTF-8编码,并且你上传的主机也要支持UTF-8文件名。如果主机支持其他非Unicode的编码方式,可以尝试用KOI8-R或WIN1251来编码文件名(不过这样做其实不太好,也不符合标准)。

补充说明,看到评论后:可能应该用 ur"C:\Users\Q\test\Тестовая папка\test.mp3".encode("UTF-8")。这里的 u 是很重要的;如果没有它,西里尔字母会按照你控制台的编码来处理。我刚试了一下,这样做是有效的(不是上传,只是 setopt)。

撰写回答