使用Python的Windows上的Unicode文件名&;subprocess.Popen()
为什么会出现以下情况:使用Python的Windows上的Unicode文件名&;subprocess.Popen(),python,windows,unicode,Python,Windows,Unicode,为什么会出现以下情况: >>> u'\u0308'.encode('mbcs') #UMLAUT '\xa8' >>> u'\u041A'.encode('mbcs') #CYRILLIC CAPITAL LETTER KA '?' >>> 我有一个Python应用程序接受来自操作系统的文件名。它适用于一些国际用户,但不适用于其他用户 例如,此unicode文件名: u'\u041a\u0433\u044b\u044b\u0448\
>>> u'\u0308'.encode('mbcs') #UMLAUT
'\xa8'
>>> u'\u041A'.encode('mbcs') #CYRILLIC CAPITAL LETTER KA
'?'
>>>
我有一个Python应用程序接受来自操作系统的文件名。它适用于一些国际用户,但不适用于其他用户
例如,此unicode文件名:
u'\u041a\u0433\u044b\u044b\u0448\u0444\u0442'
不会使用Windows“mbcs”编码(文件系统使用的编码,由sys.getfilesystemencoding()返回)。我得到“??”,表示编码器在这些字符上失败。但这毫无意义,因为文件名一开始就来自用户
更新:以下是我的背景,我的理由背后。。。
我的系统中有一个文件名为西里尔文。我想用该文件作为参数调用subprocess.Popen()。Popen无法处理unicode。通常,我可以使用sys.getfilesystemencoding()给出的编解码器对参数进行编码。在这种情况下,如果说对于Windows NT和更高版本,文件名本机是Unicode,那么它将不起作用。如果您有一个有效的unicode文件名,为什么还要麻烦使用mbcs对其进行编码 假设mbcs使用“ANSI代码页”(根据用户的区域设置而有所不同)进行编码,因此如果区域设置不使用西里尔字符,请使用splat
编辑:因此您的进程正在调用subprocess.Popen()。如果您调用的进程在您的控制之下,那么这两个进程将能够同意使用UTF-8作为Unicode传输格式。否则,您可能需要询问pywin32邮件列表。在任何情况下,请编辑您的问题以说明您对调用过程的控制程度。如果您需要传递现有文件的名称,则通过传递8.3版本的Unicode文件名可能会有更好的成功机会 您需要安装软件包,然后可以执行以下操作:
>>> import win32api
>>> win32api.GetShortPathName(u"C:\\Program Files")
'C:\\PROGRA~1'
我相信这些短文件名只使用ASCII字符,因此您应该能够将它们用作命令行的参数
如果还需要指定要创建的文件名,可以使用Unicode文件名从Python中提前创建零大小的文件名,并将文件的短名称作为参数传递
更新:用户bogdan正确地说8.3文件名生成可以被禁用(我在笔记本电脑上安装Windows XP时也禁用了它),所以你不能依赖它们。因此,在处理NTFS卷时,另一种更为牵强的方法是,可以将Unicode文件名转换为普通ASCII文件名;将ASCII文件名传递给外部命令,然后将其删除。在Py3K中-至少从Python 3.2-
子流程中。Popen
和sys.argv
与Windows上的(默认unicode)字符串一致CreateProcessW
和GetCommandLineW
被明显使用
在Python-v2.7.2之前的版本中,至少-subprocess.Popen
带有Unicode参数。它坚持使用CreateProcessA
(而os.*
与Unicode一致)。而shlex.split会产生额外的废话
Pywin32的win32process.CreateProcess
也不会自动切换到W版本,也没有win32process.CreateProcessW
。与GetCommandLine
相同。
因此,需要使用ctypes.windl.kernel32.CreateProcessW…
。
关于此问题,子流程模块可能应该得到修复
在Unicode操作系统上,带有私有应用的argv[1:://code>上的UTF8仍然很笨拙。对于像Linux这样的8位“Latin1”字符串操作系统,这些技巧可能是合法的
更新vaab为Python 2.7创建了一个修补版的Popen
,解决了这个问题。
见
带有解释的博客帖子:免责声明:我是下面提到的修复程序的作者
要在带有python 2.7的windows上支持unicode命令行,可以使用
到subprocess.Popen(..)
形势
Python 2在windows上对unicode命令行的支持非常差
被严重窃听:
- 从调用方向系统发出unicode命令行(通过
subprocess.Popen(..)
)
- 并从被调用方读取当前的命令行unicode参数(通过
sys.argv
)
在Python2上,这是公认的。这些在Python3中是固定的
技术原因
在Python2中,subprocess.Popen(…)
和sys.argv
的windows实现使用非unicode就绪的windows系统调用CreateProcess(…)
(请参见Python和MSDN),而不对sys.argv
使用GetCommandLineW(…)
在Python 3中,subprocess.Popen(..)
的windows实现使用正确的windows系统调用CreateProcessW(..)
从3.0
开始(参见3.0
)和sys.argv
使用GetCommandLineW(..)
从3.3
开始(参见3.3
)
它是如何固定的
给定的将利用ctypes
模块调用C窗口
系统直接创建进程w(..)
。它提出了一个新的固定的Popen
对象,通过覆盖私有方法Popen.\u执行子(…)
和私有函数\u子流程.CreateProcess(…)
从windows系统库中设置和使用CreateProcessW(…)
,尽可能模仿Python3.6
中的操作方式
如何使用它
下面将演示如何使用给定的补丁。它还显示了如何读取当前进程
sys.argv
with.对于Python3,只需不编码字符串即可。Windows文件名本机为Unicode,Python 3中的所有字符串均为Unicode,Popen使用Unicode版本的CreateProcess
Windows API函数
使用Python2.7