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

使用Python Mongoengine存储读取PDF 解决Heroku文件丢失问题

问题根因排查

  1. 报错No such file or directory: b''的直接原因:你错误地把art.uploaded_content.read()返回的PDF字节内容,作为文件路径传给了open()方法,open()的第一个参数需要是本地文件路径,不能直接传文件字节。另外如果读取文件后没有重置指针,后续调用read()只会返回空字节串。
  2. 报错ValueError: embedded null byte的常见原因:你生成的article_pdf_filename包含空字符或非法字符,不符合本地文件系统的命名规则。

正确的Mongoengine存储&读取PDF实现

存储逻辑修正

import uuid
from werkzeug.utils import secure_filename

# 存储PDF的路由逻辑
if request.files['uploaded-article']:
    article_pdf = request.files['uploaded-article']
    # 生成安全的随机文件名,避免空字符/非法字符问题
    original_name = secure_filename(article_pdf.filename)
    file_ext = original_name.rsplit('.', 1)[1].lower() if '.' in original_name else 'pdf'
    article_pdf_filename = f"{uuid.uuid4().hex}.{file_ext}"
    
    data = Article()
    # 直接把文件对象存入FileField,指定文件类型避免解析错误
    data.uploaded_content.put(article_pdf, content_type='application/pdf')
    data.uploaded_content_name = article_pdf_filename
    data.save()

读取逻辑修正

import os

articles = Article.objects()
for art in articles:
    save_path = os.path.join(app.config['BLOG_FOLDER'], art.uploaded_content_name)
    if not os.path.isfile(save_path):
        # 读取FileField的字节内容直接写入本地文件
        pdf_content = art.uploaded_content.read()
        with open(save_path, 'wb') as f:
            f.write(pdf_content)
        # 重置文件指针,避免后续读取返回空字节
        art.uploaded_content.seek(0)

Heroku静态文件丢失的替代方案

Heroku的文件系统是临时存储,每次部署、dyno重启都会清空所有写入的非代码内置文件,除了存MongoDB,还有几个更适配生产场景的方案:

  • 对象存储服务:将PDF、图片直接上传到阿里云OSS、腾讯云COS等对象存储服务,仅把文件的CDN访问链接存在数据库中,无需本地存储,访问速度更快,也不受Heroku临时文件系统限制。
  • 数据库直连访问:不需要把PDF读入本地静态文件夹,直接做一个路由接口,用户请求文件时实时从MongoDB读取字节返回给前端,完全跳过本地存储步骤。
  • 静态资源打包部署:如果是更新频率极低的固定文件,直接把资源存入代码仓库,和代码一起打包部署,就不会被临时文件系统清空。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 17:45:08