You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flask调用docx2pdf转docx为PDF时触发FileNotFoundError求助

Flask实现docx转PDF触发FileNotFoundError问题排查

问题现象

基于Flask框架开发docx文件转PDF功能时,程序运行触发FileNotFoundError错误,错误截图如下:
错误截图

问题复现代码

from flask import Flask
from flask import request, render_template, send_file
import os
from typing import Tuple
from docx2pdf import convert

UPLOADER_FOLDER = ''
app = Flask(__name__)
app.config['UPLOADER_FOLDER'] = UPLOADER_FOLDER

@app.route('/')
@app.route('/index', methods=['GET', 'POST'])
def index():
    if request.method == "POST":
        def docx2pdf(input_file: str, output_file: str, pages: Tuple = None):
           if pages:
               pages = [int(i) for i in list(pages) if i.isnumeric()]

           result = convert(input_file, output_file)
           print('Convert Done')
           summary = {
               "File": input_file, "Pages": str(pages), "Output File": output_file
            }
           print("\n".join("{}:{}".format(i, j) for i, j in summary.items()))
           return result
        file = request.files['filename']
        if file.filename!= '':
           file.save(os.path.join(app.config['UPLOADER_FOLDER'], file.filename))
           input_file = file.filename
           output_file = r"hello.pdf"
           docx2pdf(input_file, output_file)
           pdf = input_file.split(".")[0]+".pdf"
           print(pdf)
           lis=pdf.replace(" ", "=")
           os.rename("hello.pdf", lis)
           print('converted')
           return render_template("docx.html", variable=lis)
    return render_template("index.html")


@app.route('/docx', methods=['GET', 'POST'])
def docx():
    if request.method=="POST":
        lis = request.form.get('filename', None)
        lis = lis.replace("=", " ")
        return send_file(lis, as_attachment=True)
    return render_template("index.html")

if __name__=="__main__":
    app.debug = True
    app.run()

报错原因

  • 路径配置不规范:UPLOADER_FOLDER设置为空字符串,所有文件读写、转换、返回操作都使用相对路径,Flask启动时工作目录一旦和预期不符,程序就无法定位到上传的docx文件、生成的PDF文件,直接触发文件找不到错误。
  • 依赖环境不满足:docx2pdf库本身没有格式转换能力,底层是调用系统安装的桌面版Microsoft Word组件完成格式转换,Windows下依赖COM组件、macOS下依赖AppleScript调用Word,如果运行环境没有安装桌面版Word(比如无GUI的Linux服务器、精简版Windows系统),库启动Word进程失败也会抛出FileNotFoundError。
  • 代码逻辑缺陷:文件保存时用了os.path.join拼接上传目录,但后续转换、重命名、返回文件环节都没有拼接完整路径,直接传裸文件名;另外将转换函数嵌套在路由请求逻辑内,每次请求重复定义函数,容易触发Word进程锁、文件句柄未释放的问题,间接导致文件访问失败。
  • 文件名处理逻辑冗余:代码中将文件名空格替换为=的操作没有实际意义,反而会增加路径解析错误的概率;固定使用hello.pdf作为临时输出名,多请求并发时会出现文件覆盖冲突。

修复方案

  1. 配置固定绝对路径作为上传存储目录,自动创建不存在的目录,替换原空值配置:
# 基于当前脚本所在目录生成uploads文件夹的绝对路径
UPLOADER_FOLDER = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'uploads')
if not os.path.exists(UPLOADER_FOLDER):
    os.makedirs(UPLOADER_FOLDER)
app.config['UPLOADER_FOLDER'] = UPLOADER_FOLDER
  1. 将转换函数移到路由外部定义,所有文件操作统一拼接上传目录的绝对路径,禁止直接使用裸文件名做操作。
  2. 确认运行环境安装了完整的桌面版Microsoft Word,不要在无GUI的Linux服务器上使用该方案,Linux环境建议替换为LibreOffice+unoconv的方案实现格式转换。
  3. 去掉无意义的文件名特殊字符替换逻辑,输出PDF直接使用原文件对应名称,避免多请求文件覆盖问题。
  4. 修复后核心代码参考:
# 转换函数挪到路由外部全局定义
def docx2pdf(input_file: str, output_file: str, pages: Tuple = None):
    if pages:
        pages = [int(i) for i in list(pages) if i.isnumeric()]
    result = convert(input_file, output_file)
    print('Convert Done')
    summary = {
        "File": input_file, "Pages": str(pages), "Output File": output_file
    }
    print("\n".join("{}:{}".format(i, j) for i, j in summary.items()))
    return result

@app.route('/')
@app.route('/index', methods=['GET', 'POST'])
def index():
    if request.method == "POST":
        file = request.files['filename']
        if file.filename!= '':
            # 拼接输入文件绝对路径
            input_path = os.path.join(app.config['UPLOADER_FOLDER'], file.filename)
            file.save(input_path)
            # 生成对应输出PDF的绝对路径
            output_filename = f"{os.path.splitext(file.filename)[0]}.pdf"
            output_path = os.path.join(app.config['UPLOADER_FOLDER'], output_filename)
            docx2pdf(input_path, output_path)
            return render_template("docx.html", variable=output_filename)
    return render_template("index.html")

@app.route('/docx', methods=['GET', 'POST'])
def docx():
    if request.method=="POST":
        filename = request.form.get('filename', None)
        # 拼接待下载文件的绝对路径
        file_path = os.path.join(app.config['UPLOADER_FOLDER'], filename)
        return send_file(file_path, as_attachment=True)
    return render_template("index.html")

本地测试如果依然报错,先手动打开Word确认能正常启动,关闭首次启动的许可提示、登录弹窗,这类弹窗会阻塞COM调用导致库无法唤起Word进程。

内容的提问来源于stack exchange,提问作者Mixhalo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 13:01:01