Unicode文件名到python subprocess.call()

otr*_*rov 10 python unicode subprocess call

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

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

subprocess.call(n + f)
Run Code Online (Sandbox Code Playgroud)

这提出了一个着名的错误:

UnicodeEncodeError:'ascii'编解码器不能编码字符u'\ xe8'

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

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

谢谢

Red*_*rav 7

我找到了一个很好的解决方法,它有点凌乱,但它的工作原理.

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

下列

notepad = 'C://Notepad.exe'
subprocess.call([notepad.encode(sys.getfilesystemencoding())])
Run Code Online (Sandbox Code Playgroud)

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

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

os.cwd() 
Run Code Online (Sandbox Code Playgroud)

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

os.cwd().decode(sys.getfilesystemencoding())
Run Code Online (Sandbox Code Playgroud)

这与上面的解决方案非常相似.

希望能帮助到你.


WGH*_*WGH 6

如果您的文件存在,您可以使用短文件名(又名8.3名称).此名称是为现有文件定义的,并且在作为参数传递时不会对非Unicode感知程序造成任何麻烦.

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

import win32api
short_path = win32api.GetShortPathName(unicode_path)
Run Code Online (Sandbox Code Playgroud)

或者,您也可以使用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
Run Code Online (Sandbox Code Playgroud)

  • 呵呵,这真是太恶心了!虽然方便. (2认同)

小智 0

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