Unicode文件名到python subprocess.call()

时间:2010-04-07 19:53:07

标签: python unicode subprocess call

我正在尝试使用unicode文件名运行subprocess.call(),这是简化的问题:

n = u'c:\\windows\\notepad.exe '
f = u'c:\\temp\\nèw.txt'

subprocess.call(n + f)

引发了一个着名的错误:

  

UnicodeEncodeError:'ascii'编解码器无法编码字符u'\ xe8'

编码到utf-8会产生错误的文件名,而mbcs会将文件名传递给new.txt而不需要重音

我只是无法阅读这个令人困惑的主题并旋转圈子。我在这里找到了很多不同问题的答案,所以我想加入并自己寻求帮助

由于

7 个答案:

答案 0 :(得分:6)

如果您的文件存在,您可以使用short filename(又名8.3名称)。此名称已定义 对于现有文件,当作为参数传递时,应该对非Unicode感知程序没有任何麻烦。

获得一种方法(需要Pywin32安装):

import win32api
short_path = win32api.GetShortPathName(unicode_path)

或者,您也可以使用ctypes

import ctypes
import ctypes.wintypes

ctypes.windll.kernel32.GetShortPathNameW.argtypes = [
    ctypes.wintypes.LPCWSTR, # lpszLongPath
    ctypes.wintypes.LPWSTR, # lpszShortPath
    ctypes.wintypes.DWORD # cchBuffer
]
ctypes.windll.kernel32.GetShortPathNameW.restype = ctypes.wintypes.DWORD

buf = ctypes.create_unicode_buffer(1024) # adjust buffer size, if necessary
ctypes.windll.kernel32.GetShortPathNameW(unicode_path, buf, len(buf))

short_path = buf.value

答案 1 :(得分:6)

我找到了一个很好的解决方法,它有点乱,但它确实有用。

subprocess.call将把自己编码的文本传递给终端,终端可能是也不是它所期望的那个。因为你想让它变得可移植,所以你需要在运行时知道机器的编码。

以下

notepad = 'C://Notepad.exe'
subprocess.call([notepad.encode(sys.getfilesystemencoding())])

尝试找出当前编码,因此将正确的编码应用于subprocess.call

作为旁注,我还发现如果您尝试使用当前目录撰写字符串,请使用

os.cwd() 

Python(或操作系统,不知道)会弄乱带有重音字符的目录。为了防止这种情况,我找到了以下工作:

os.cwd().decode(sys.getfilesystemencoding())

这与上述解决方案非常相似。

希望它有所帮助。

答案 2 :(得分:1)

为了使这项工作,似乎必须修改子流程代码以使用CreateProcess的宽字符版本(假设存在一个)。有一个PEP正在讨论http://www.python.org/dev/peps/pep-0277/对文件对象所做的相同更改。也许您可以研究Windows C调用并为子进程提出类似的更改。

答案 3 :(得分:0)

我没有给你答案,但我已经对这个问题进行了大量的研究。 Python将所有输出(包括系统调用)转换为与其运行的终端相同的字符.Windows终端使用代码页进行字符映射;默认代码页是437,但可以使用chcp命令更改它。 chcp 65001理论上会将代码页改为utf-8,但据我所知,python不知道如何处理这个问题,所以你是SOL。

答案 4 :(得分:0)

您可以尝试将文件打开为:

subprocess.call((n + f).encode("cp437"))

或在命令提示符窗口中使用的任何代码页chcp报告。如果您尝试以chcp 65001作为星巴克建议,则必须先编辑stdlib编码\ aliases.py文件,然后将cp65001添加为'utf-8'的别名。这是Python源代码中的一个开放性问题。

更新:由于这是一个多目标方案,因此在运行此类命令之前,请确保首先运行单个chcp命令,分析输出并检索当前的“命令提示符”(DOS)代码页。随后,使用发现的代码页对subprocess.call参数进行编码。

答案 5 :(得分:0)

正如ΤΖΩΤΖΙΟΥ和starbuck所提到的,问题在于控制台代码页,在你的情况下是866(在俄语本地化的windows中)而不是1251.只需在控制台中运行chcp

问题与将输出unicode输出到Windows控制台时的问题相同。不幸的是,您至少需要在编码\ aliases.py中为unicode命名和别名为'cp866'(或者在脚本启动时以编程方式执行),并在运行记事本之前将控制台的代码页更改为65001,然后再将其设置为

chcp 65001 & c:\WINDOWS\notepad.exe nèw.txt & chcp 866

顺便说一下,为了能够在控制台中运行命令并正确查看文件名,您需要在控制台窗口属性中将控制台字体更改为Lucida Console。

可能更糟糕的是:您需要更改当前进程的代码页。为此,您需要在脚本启动之前运行chcp 65001,或者使用pywin32在脚本中执行此操作。

答案 6 :(得分:0)

os.startfile与操作编辑一起使用。这样可以更好地工作,因为它将打开您的扩展程序的默认应用程序。