这个场景下,在用户下载完转换好的文件再删除临时文件的最佳实际是什么? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
drymonfidelia
V2EX    Python

这个场景下,在用户下载完转换好的文件再删除临时文件的最佳实际是什么?

  •  
  •   drymonfidelia 2024-07-29 06:00:33 +08:00 3286 次点击
    这是一个创建于 505 天前的主题,其中的信息可能已经有所发展或是发生改变。
    from flask import Flask, request, send_file, abort import ffmpeg import os import tempfile import time app = Flask(__name__) @app.route('/audio_appledevices/<name>.m4a', methods=['GET']) def convert_audio(name): ogg_path = f'./audio/{name}.ogg' if not os.path.exists(ogg_path): abort(404) with tempfile.NamedTemporaryFile(delete=False, suffix='.m4a') as temp_file: m4a_path = temp_file.name try: ffmpeg.input(ogg_path).output(m4a_path, codec='alac').run(overwrite_output=True) respOnse= send_file(m4a_path, as_attachment=True, download_name=f'{name}.m4a', mimetype='audio/mp4') @response.call_on_close def cleanup(): time.sleep(1) if os.path.exists(m4a_path): os.remove(m4a_path) return response except ffmpeg.Error as e: abort(500) if __name__ == '__main__': app.run(host='127.0.0.1', port=3389) 

    除非另开一个线程,不管怎么写临时文件都不能被自动删掉,要不就是 ffmpeg 写不进文件,因为临时文件被占用。 因为 ffmpeg 需要 seekable 的流,所以输出到 IO 流不可行。

    请先测试再回复!我让 GPT-4 写了几十个版本,没有一个能用。

    请先测试再回复!我让 GPT-4 写了几十个版本,没有一个能用。

    请先测试再回复!我让 GPT-4 写了几十个版本,没有一个能用。

    请先测试再回复!我让 GPT-4 写了几十个版本,没有一个能用。

    27 条回复    2024-07-30 22:37:09 +08:00
    esile
        1
    esile  
       2024-07-29 06:44:37 +08:00 via Android
    当然异步队列处理+定时删除
    expy
        2
    expy  
       2024-07-29 08:08:27 +08:00
    try except 一般在 finally 里清理吧。

    偏题一下,你这 ogg 转 alac ,ogg 是无损吗?
    ho121
        3
    ho121  
       2024-07-29 08:16:32 +08:00 via Android
    用临时目录 tempfile.TemporaryDirectory ,所有临时文件写到这个目录里,任务结束后删掉整个目录
    sunnysab
        4
    sunnysab  
       2024-07-29 08:40:13 +08:00 via Android
    猜想:tempfile 是基于操作系统临时文件功能实现的(原理是,Windows 下 CreateFile 有个参数指示,Linux 下有 open )。尝试把 delete 参数置为 True (默认值)。
    另外,有没有可能是共享写的问题,把打开方式设为 'r+b'。ffmpeg 需要处于同一用户中,这点是应该满足的,实在不行 strace 一下看看是哪一步无权限。

    捉个虫,标题中应该是“最佳实践”,而不是“最佳实际”。
    sazima
        5
    sazima  
       2024-07-29 09:37:23 +08:00
    bytesio:

    ```python
    process = (
    ffmpeg
    .input(ogg_path)
    .output('pipe:', format='wav')
    .run_async(pipe_stdout=True, pipe_stderr=True)
    )
    out, err = process.communicate()
    io = BytesIO(out)

    # 创建响应并设置合适的头信息
    respOnse= make_response(send_file(io, mimetype='application/octet-stream', as_attachment=True, download_name='example.mp3'))
    response.headers['Content-Disposition'] = 'attachment; filename=example.bin'
    return response
    ```
    sazima
        6
    sazima  
       2024-07-29 09:38:07 +08:00
    更正:
    response.headers['Content-Disposition'] = 'attachment; filename=example.mp3'
    Haku
        7
    Haku  
       2024-07-29 09:41:48 +08:00
    定时任务删除转换完后超过 x 天的文件。
    rsyjjsn
        8
    rsyjjsn  
       2024-07-29 09:45:13 +08:00   4
    网友只是提供一个解决问题的思路给你,你咋老想着网友写好代码,测试通过,原封不动的回复给你呢?
    justNoBody
        9
    justNoBody  
       2024-07-29 09:53:19 +08:00   3
    > 请先测试再回复!我让 GPT-4 写了几十个版本,没有一个能用。

    ???测试再回复???你给我 3000 美金我考虑一下
    0o0O0o0O0o
        10
    0o0O0o0O0o  
       2024-07-29 09:56:44 +08:00
    你这天天提上班遇到的问题面向 V2EX 上班已经不满足了,还要回答的人自行测试。。。工资给大伙分一下吧
    lsk569937453
        11
    lsk569937453  
       2024-07-29 09:58:29 +08:00
    笑死。。。。这是面向 V2EX 编程的社会实践吗?
    Hopetree
        12
    Hopetree  
       2024-07-29 09:59:23 +08:00
    既然是临时文件,当然是规定好清理规则,定时任务定时清理 N 天前生成的文件啊,又简单又快速
    lzZzeucJri6FcR0o
        13
    lzZzeucJri6FcR0o  
       2024-07-29 10:03:41 +08:00
    很难想象这是求问的态度
    Wh1t3zZ
        14
    Wh1t3zZ  
       2024-07-29 10:03:58 +08:00   1
    伸手党还这么理直气壮?
    gwy15
        15
    gwy15  
       2024-07-29 10:17:15 +08:00
    我欠你的
    deplives
        16
    deplives  
       2024-07-29 11:04:17 +08:00
    原来 op 就是那个 CORS 和 CSRF 都分不清的人 https://v2ex.com/t/1057881
    deplives
        17
    deplives  
       2024-07-29 11:06:29 +08:00

    原来是站长亲戚,怪不得这么理直气壮的伸手
    drymonfidelia
        18
    drymonfidelia  
    OP
       2024-07-29 11:08:00 +08:00
    @expy 不是,所以要定时删除,ogg 源文件有几 TB
    @ho121 @sunnysab 这两种方案我都尝试了,执行到 return 那边就会因为文件被 flask 占用无法删除报 500 错误
    @sazima 需要 alac 的输出,alac 需要 seekable 的流
    @rsyjjsn
    @justNoBody
    @0o0O0o0O0o
    @lsk569937453
    @djasdjds
    @gwy15 这个问题远没有那么容易解决,我已经想到会有大量无效答案了,写一下试试能不能减少一些
    vituralfuture
        19
    vituralfuture  
       2024-07-29 12:00:45 +08:00 via Android   1
    没能把答案喂给你真是抱歉
    drymonfidelia
        20
    drymonfidelia  
    OP
       2024-07-29 16:14:07 +08:00
    @rsyjjsn
    @justNoBody
    @0o0O0o0O0o
    @lsk569937453
    @djasdjds
    @gwy15 只是讨论最佳实践,我已经用脏实现写了个 cron 定时 rm * 来交差了,知道最佳实践也不会比别人得到更多好处
    不会可以不回答,没必要只会阴阳怪气
    amlee
        21
    amlee  
       2024-07-29 17:00:18 +08:00
    @drymonfidelia 不会可以不要问,没必要理直气壮
    tomczhen
        22
    tomczhen  
       2024-07-29 17:12:02 +08:00
    写了,测了,但是不想发了。( doge
    tangtang369
        23
    tangtang369  
       2024-07-29 17:18:31 +08:00
    这样好像可以删除掉
    ```
    from flask import Flask, request, send_file, abort,after_this_request
    import ffmpeg
    import os
    import tempfile
    import time

    app = Flask(__name__)

    @app.route('/audio_appledevices/<name>.m4a', methods=['GET'])
    def convert_audio(name):
    ogg_path = f'./audio/{name}.ogg'
    if not os.path.exists(ogg_path):
    abort(404)
    with tempfile.NamedTemporaryFile(delete=False, suffix='.m4a') as temp_file:
    m4a_path = temp_file.name
    try:
    ffmpeg.input(ogg_path).output(m4a_path, codec='alac').run(overwrite_output=True)
    respOnse= send_file(m4a_path, as_attachment=True, download_name=f'{name}.m4a', mimetype='audio/mp4')
    print("run m4a_path",m4a_path)

    @after_this_request
    def cleanup(response):
    print("run cleanup")
    time.sleep(1)
    if os.path.exists(m4a_path):
    os.remove(m4a_path)
    return response
    return response
    except ffmpeg.Error as e:
    abort(500)


    if __name__ == '__main__':
    app.run(host='127.0.0.1', port=3389)
    ```
    lzZzeucJri6FcR0o
        24
    lzZzeucJri6FcR0o  
       2024-07-29 18:20:25 +08:00
    @drymonfidelia #20 牛皮
    drymonfidelia
        25
    drymonfidelia  
    OP
       2024-07-29 19:06:19 +08:00
    @tangtang369 还是没有删除掉,in cleanup
    os.remove(m4a_path)
    PermissionError: [WinError 32] The process cannot access the file because it is being used by another process
    tangtang369
        26
    tangtang369  
       2024-07-30 09:14:47 +08:00
    @drymonfidelia #25 你是 windows 吗 这个我 mac 和 linux 测了没啥问题
    drymonfidelia
        27
    drymonfidelia  
    OP
       2024-07-30 22:37:09 +08:00 via iPhone
    @tangtang369 是的,可能是因为 Windows 的问题
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5170 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 53ms UTC 07:39 PVG 15:39 LAX 23:39 JFK 02:39
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86