美文网首页
FileNotFoundError: [WinError 2]

FileNotFoundError: [WinError 2]

作者: Bllose | 来源:发表于2023-08-27 22:09 被阅读0次

    报错现场

    报错反复出现,每次解决一个问题,又因为下一个文件找不到而报错。

    C:\etc\Python\Python39\python.exe "C:/Program Files/JetBrains/PyCharm 2022.2.2/plugins/python/helpers/pydev/pydevd.py" --multiprocess --qt-support=auto --client 127.0.0.1 --port 51307 --file C:\workplace\github.com\***\sources\medias\BMedia.py 
    Connected to pydev debugger (build 222.4167.33)
    Traceback (most recent call last):
      File "C:\etc\Python\Python39\lib\subprocess.py", line 951, in __init__
        self._execute_child(args, executable, preexec_fn, close_fds,
      File "C:\etc\Python\Python39\lib\subprocess.py", line 1420, in _execute_child
        hp, ht, pid, tid = _winapi.CreateProcess(executable, args,
      File "C:\Program Files\JetBrains\PyCharm 2022.2.2\plugins\python\helpers\pydev\_pydev_bundle\pydev_monkey.py", line 578, in new_CreateProcess
        return getattr(_subprocess, original_name)(app_name, patch_arg_str_win(cmd_line), *args)
    FileNotFoundError: [WinError 2] 系统找不到指定的文件。
    python-BaseException
    Backend QtAgg is interactive backend. Turning interactive mode on.
    

    解决办法

    Windows 系统

    1. 下载安装 ImageMagick ; ffmpeg-release-essentials.zip
    2. 设置环境变量


      IMAGEMAGICK_BINARY
      FFMPEG_BINARY
      ffmpeg_bin_path

    关键代码展示

    moviepy.config.py

    config_defaults.py 编写了针对 ffmpeg, imagemagick 的默认值获取

    import os
    
    FFMPEG_BINARY = os.getenv('FFMPEG_BINARY', 'ffmpeg-imageio')
    IMAGEMAGICK_BINARY = os.getenv('IMAGEMAGICK_BINARY', 'auto-detect')
    

    config.py 尝试加载 ffmpeg, imagemagick 资源

    if IMAGEMAGICK_BINARY=='auto-detect':
        if os.name == 'nt':
            try:
                key = wr.OpenKey(wr.HKEY_LOCAL_MACHINE, 'SOFTWARE\\ImageMagick\\Current')
                IMAGEMAGICK_BINARY = wr.QueryValueEx(key, 'BinPath')[0] + r"\convert.exe"
                key.Close()
            except:
                IMAGEMAGICK_BINARY = 'unset'
        elif try_cmd(['convert'])[0]:
            IMAGEMAGICK_BINARY = 'convert'
        else:
            IMAGEMAGICK_BINARY = 'unset'
    else:
        if not os.path.exists(IMAGEMAGICK_BINARY):
            raise IOError(
                "ImageMagick binary cannot be found at {}".format(
                    IMAGEMAGICK_BINARY
                )
            )
    
        if not os.path.isfile(IMAGEMAGICK_BINARY):
            raise IOError(
                "ImageMagick binary found at {} is not a file".format(
                    IMAGEMAGICK_BINARY
                )
            )
    
        success, err = try_cmd([IMAGEMAGICK_BINARY])
        if not success:
            raise IOError("%s - The path specified for the ImageMagick binary might "
                          "be wrong: %s" % (err, IMAGEMAGICK_BINARY))
    

    moviepy.config_defaults.py

    if FFMPEG_BINARY=='ffmpeg-imageio':
        from imageio.plugins.ffmpeg import get_exe
        FFMPEG_BINARY = get_exe()
    
    elif FFMPEG_BINARY=='auto-detect':
    
        if try_cmd(['ffmpeg'])[0]:
            FFMPEG_BINARY = 'ffmpeg'
        elif try_cmd(['ffmpeg.exe'])[0]:
            FFMPEG_BINARY = 'ffmpeg.exe'
        else:
            FFMPEG_BINARY = 'unset'
    else:
        success, err = try_cmd([FFMPEG_BINARY])
        if not success:
            raise IOError(
                str(err) +
                " - The path specified for the ffmpeg binary might be wrong")
    

    很显然, 系统没有指定资源文件时,moviepy会自己尝试加载。只不过找不到的时候抛出异常。

    pydub.utils.py

    最关键的部分是,pydub借用了avprobe、ffprobe来完成它的逻辑。
    而借用的方式就是调用subprocess.Popen创建子线程,直接调用操作系统,执行ffprobe工具。
    此处报错找不到文件就是因为在环境中我当时并未配置 ffprobe所在目录,所以Popen在执行命令ffprobe时,自然就作为找不到ffprobe这个文件的异常爆出来了。

    def mediainfo_json(filepath, read_ahead_limit=-1):
        """Return json dictionary with media info(codec, duration, size, bitrate...) from filepath
        """
        prober = get_prober_name()
        command_args = [
            "-v", "info",
            "-show_format",
            "-show_streams",
        ]
        try:
            command_args += [fsdecode(filepath)]
            stdin_parameter = None
            stdin_data = None
        except TypeError:
            if prober == 'ffprobe':
                command_args += ["-read_ahead_limit", str(read_ahead_limit),
                                 "cache:pipe:0"]
            else:
                command_args += ["-"]
            stdin_parameter = PIPE
            file, close_file = _fd_or_path_or_tempfile(filepath, 'rb', tempfile=False)
            file.seek(0)
            stdin_data = file.read()
            if close_file:
                file.close()
    
        command = [prober, '-of', 'json'] + command_args
        res = Popen(command, stdin=stdin_parameter, stdout=PIPE, stderr=PIPE)
        output, stderr = res.communicate(input=stdin_data)
        output = output.decode("utf-8", 'ignore')
        stderr = stderr.decode("utf-8", 'ignore')
    
        info = json.loads(output)
    # ... 后续代码省略
    

    这段代码就是他尝试找到系统中的avprobe命令,或者ffprobe命令。 如果都找不到就会警告:我只能使用默认配置,但是可能运行不了~

    def get_prober_name():
        """
        Return probe application, either avconv or ffmpeg
        """
        if which("avprobe"):
            return "avprobe"
        elif which("ffprobe"):
            return "ffprobe"
        else:
            # should raise exception
            warn("Couldn't find ffprobe or avprobe - defaulting to ffprobe, but may not work", RuntimeWarning)
            return "ffprobe"
    

    这段代码就是具体寻找的过程了。显然,它遍历了系统环境中配置的路径,所有路径都会尝试找命令,本质上跟在cmd中输入命令,系统查找可以运行的工具是一个逻辑。

    def which(program):
        """
        Mimics behavior of UNIX which command.
        """
        # Add .exe program extension for windows support
        if os.name == "nt" and not program.endswith(".exe"):
            program += ".exe"
    
        envdir_list = [os.curdir] + os.environ["PATH"].split(os.pathsep)
    
        for envdir in envdir_list:
            program_path = os.path.join(envdir, program)
            if os.path.isfile(program_path) and os.access(program_path, os.X_OK):
                return program_path
    

    再次运行效果

    Success Popen: returncode

    相关文章

      网友评论

          本文标题:FileNotFoundError: [WinError 2]

          本文链接:https://www.haomeiwen.com/subject/oqgwmdtx.html