Python 从tk对话框返回的UTF-8文件名的UnicodeError
您好,我正在尝试使用Python 从tk对话框返回的UTF-8文件名的UnicodeError,python,unicode,encoding,subprocess,Python,Unicode,Encoding,Subprocess,您好,我正在尝试使用ffmpeg和以下函数(在python2中)从视频文件中提取音频: 上述打印语句成功打印以下内容: ffmpeg -i "C:/Users/pruthvi/Desktop/vidrec/temp\TAEYEON 태연_ I (feat. Verbal Jint)_Music Video.mp4" -ab 160k -ac 2 -ar 44100 -vn audio.wav 但在下一条语句中,它失败并抛出以下错误: Traceback (most recent call la
ffmpeg
和以下函数(在python2
中)从视频文件中提取音频:
上述打印语句成功打印以下内容:
ffmpeg -i "C:/Users/pruthvi/Desktop/vidrec/temp\TAEYEON 태연_ I (feat. Verbal Jint)_Music Video.mp4" -ab 160k -ac 2 -ar 44100 -vn audio.wav
但在下一条语句中,它失败并抛出以下错误:
Traceback (most recent call last):
File "C:/Users/pruthvi/Desktop/vidrec/vidrec.py", line 53, in <module>
main()
File "C:/Users/pruthvi/Desktop/vidrec/vidrec.py", line 46, in main
extractAudio(os.path.join(di,each))
File "C:/Users/pruthvi/Desktop/vidrec/vidrec.py", line 28, in extractAudio
subprocess.call(command,shell=True)
File "C:\Python27\lib\subprocess.py", line 522, in call
return Popen(*popenargs, **kwargs).wait()
File "C:\Python27\lib\subprocess.py", line 710, in __init__
errread, errwrite)
File "C:\Python27\lib\subprocess.py", line 928, in _execute_child
args = '{} /c "{}"'.format (comspec, args)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 56-57: ordinal not in range(128)
因为您要将unicode字符串传递给
子流程.call
,Python尝试将其编码为它认为文件系统/操作系统能够理解的编码。出于某种原因,选择ASCII是错误的
您可以通过以下方式尝试使用正确的编码:
subprocess.call(command.encode(sys.getfilesystemencoding()))
与上一个问题相同:Windows上的大多数跨平台软件无法处理文件名中的非ASCII字符 Python的
子流程
模块使用基于字节字符串的接口。在Windows下,命令行基于Unicode字符串(技术上是UTF-16代码单元),因此MS C运行时使用不同机器的编码(“ANSI”代码页)将字节字符串转换为Unicode字符串,该编码不能包含所有Unicode字符
如果您的Windows安装是韩文的,您的ANSI代码页将是949韩文的,您可以通过以下方式之一编写命令:
subprocess.call(command.encode('cp949'))
subprocess.call(command.encode('mbcs'))
(其中,mbcs
是“多字节字符集”的缩写,它是Windows上ANSI代码页的同义词。)如果您的安装不是韩语的,您将有一个不同的ANSI代码页,并且您将无法将该文件名写入命令,因为您的命令行编码中没有任何韩语。ANSI编码从来都不像UTF-8那样合理,因此没有人能够可靠地使用子流程来执行包含所有Unicode字符的命令
如前一个问题中所讨论的,Python包括Unicode文件名的变通方法,以使用本机Win32 API而不是C标准库。在Python3中,它还使用Win32 Unicode API来创建进程,但在Python2中情况并非如此。您可以通过ctypes
调用Win32CreateProcessW
命令,直接访问Windows API,但这有点麻烦
…而且它无论如何都没有用,因为即使您将非ANSI字符输入命令行,ffmpeg
命令本身也会失败。这是因为ffmpeg也是一个跨平台应用程序,它使用C标准库读取命令行和文件。它将无法读取命令行参数中的韩语,即使您以某种方式通过了它,它也无法读取该名称的文件
这是Windows平台上令人沮丧的一个原因:尽管它在内部非常支持Unicode,但大多数运行在它上面的工具却不能。答案应该是Windows在它实现的所有字节字符串接口中都支持UTF-8,而不是没有人想要的陈旧的ANSI代码页。不幸的是,微软一再拒绝采取让UTF-8在Windows上成为一流公民的第一步(即修复一些阻止UTF-8在控制台上工作的bug)。对不起
无关:这:
''.join(('ffmpeg -i "',path,'"...
这通常是个坏主意。文件名中有许多特殊字符会中断该命令行,并可能最终执行各种其他命令。如果输入路径由不受信任的人控制,这将是一个严重的安全漏洞。通常,当您将变量的命令行放在一起时,您需要应用转义以使字符串可以安全地包含在内,并且Windows上的转义规则非常复杂且烦人
通过将所有内容保留在Python中,可以避免转义问题和Unicode问题。您可以使用将ffmpeg的功能引入Python的模块,例如PyFFmpeg,而不是启动调用ffmpeg代码的命令
或者一个廉价的“n”或“n”蹩脚的解决方法是将文件复制/移动到Python中已知的安全名称,使用静态文件名运行ffmpeg
命令,然后重命名/复制回文件…您有两个问题:
Python 2
在任何参数中使用Unicode时,子流程
模块将中断。这个问题在Python3中得到了修复,您可以将任何Unicode文件名和参数传递给子进程
,它将正确地将它们转发给子进程
ffmpeg
ffmpeg本身无法打开这些文件,您只需尝试从命令行运行即可轻松验证:
C:\temp>fancy αβγ.m4v
... lots of other output
fancy a�?.m4v: Invalid data found when processing input
(我的代码页是windows-1252,请注意希腊字母a是如何被拉丁字母a替换的。)
您无法解决此问题,但可以解决此问题,请参见bobince的答案。作为临时解决方案,我将文件复制为非unicode名称,然后将其传递给
子流程
,我仍然想知道如何解决上述问题。如果您去掉shell=True
并执行子流程,会发生什么情况(['ffmpeg','-i',path',ab',160k','-ac',2','-ar',44100','-vn',audio.wav'])
?@bbayles同样的错误,刚刚尝试过。我注意到path
有一个反斜杠和一个正斜杠。我不认为这会导致问题,但你是否尝试过使它保持一致的正斜杠?@bbayles我使用了os.path.join(目录,文件)
,它还解释了为什么以及如何丢失shell=True
这个讨厌的东西。这会抛出TypeError:必须是没有空字节的字符串或没有,而不是str
当您编码到utf-8时会发生什么?还有sys.getfilesystemencoding()的输出是什么
?OP使用的是Python 2.7,因此他传入了一个字节字符串。我认为这种解释不正确,文档实际上提到“在Windows上,类使用Windows CreateProcess()”。它只是Python 2.x内部使用byte str
''.join(('ffmpeg -i "',path,'"...
C:\temp>fancy αβγ.m4v
... lots of other output
fancy a�?.m4v: Invalid data found when processing input