Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/302.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 从tk对话框返回的UTF-8文件名的UnicodeError_Python_Unicode_Encoding_Subprocess - Fatal编程技术网

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
调用Win32
CreateProcessW
命令,直接访问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