Windows下修复PyDub重开文件引发Errno 13权限错误的稳健方案
PyDub播放WAV文件时的PermissionError([Errno 13])问题排查
问题场景与报错信息
我正在学习PyDub,首个练习是播放WAV文件,适配后的代码如下。当前重点解决执行play(wav_file)时出现的[Errno 13]错误,暂不关注警告:
>>> import os >>> os.chdir('C:/cygwin64/home/User.Name/Some.Path') >>> from pydub import AudioSegment >>> from pydub.playback import play >>> wav_file = AudioSegment.from_file(file = "SomeFile.wav", format = "wav") C:\Users\User.Name\anaconda3\envs\py39\lib\site-packages\pydub\utils.py:170: RuntimeWarning: Couldn't find ffmpeg or avconv - defaulting to ffmpeg, but may not work warn("Couldn't find ffmpeg or avconv - defaulting to ffmpeg, but may not work", RuntimeWarning) >>> play(wav_file) C:\Users\User.Name\anaconda3\envs\py39\lib\site-packages\pydub\utils.py:184: RuntimeWarning: Couldn't find ffplay or avplay - defaulting to ffplay, but may not work warn("Couldn't find ffplay or avplay - defaulting to ffplay, but may not work", RuntimeWarning) Traceback (most recent call last): Cell In[5], line 1 play(wav_file) File ~\anaconda3\envs\py39\lib\site-packages\pydub\playback.py:71 in play _play_with_ffplay(audio_segment) File ~\anaconda3\envs\py39\lib\site-packages\pydub\playback.py:15 in _play_with_ffplay seg.export(f.name, "wav") File ~\anaconda3\envs\py39\lib\site-packages\pydub\audio_segment.py:867 in export out_f, _ = _fd_or_path_or_tempfile(out_f, 'wb+') File ~\anaconda3\envs\py39\lib\site-packages\pydub\utils.py:60 in _fd_or_path_or_tempfile fd = open(fd, mode=mode) PermissionError: [Errno 13] Permission denied: 'C:\\Users\\User.Name\\AppData\\Local\\Temp\\tmpryjpscsv.wav'
问题分析
已确认用户账户拥有Temp文件夹写入权限,经搜索得知Windows下重复打开未关闭的文件可能导致该错误。堆栈跟踪最后指向utils.py第60行,此处存在重复打开风险:
/c/Users/User.Name/anaconda3/envs/py39/lib/site-packages/pydub/utils.py ----------------------------------------------------------------------- 53 def _fd_or_path_or_tempfile(fd, mode='w+b', tempfile=True): 54 close_fd = False 55 if fd is None and tempfile: 56 fd = TemporaryFile(mode=mode) 57 close_fd = True 58 59 if isinstance(fd, basestring): 60 fd = open(fd, mode=mode) 61 close_fd = True 62 63 try: 64 if isinstance(fd, os.PathLike): 65 fd = open(fd, mode=mode) 66 close_fd = True 67 except AttributeError: 68 # module os has no attribute PathLike, so we're on python < 3.6. 69 # The protocol we're trying to support doesn't exist, so just pass. 70 pass 71 72 return fd, close_fd
修改尝试与疑问
注意到当fd被赋值为打开的文件时,close_fd标志会设为True,可借此避免重复打开。第60和65行是[Errno 13]的潜在触发点,考虑将前置if条件修改为以下形式,不确定是否稳健:
59 if not close_fd and isinstance(fd, basestring): 64 if not close_fd and isinstance(fd, os.PathLike):
第二个条件涉及os.PathLike,暂未完全理解其含义及外层try块的作用,但希望微观逻辑足够通用。
补充说明:已按上述方式修改第59和64行,但问题未解决,行为无变化。不想采用提前关闭文件的方案,因TemporaryFile()创建的临时文件关闭后会消失;且第60行执行前fd只是字符串,第56行执行前fd为None,无法关闭;此外close_fd标志的设计显然希望延迟关闭文件。
内容的提问来源于stack exchange,提问作者user2153235
相关产品推荐
相关产品推荐

