我正在尝试使用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而不需要重音
我只是无法阅读这个令人困惑的主题并旋转圈子。我在这里找到了很多不同问题的答案,所以我想加入并自己寻求帮助
由于
答案 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
与操作编辑一起使用。这样可以更好地工作,因为它将打开您的扩展程序的默认应用程序。