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

Django创建FileResponse时为何返回WinError32权限错误?

问题:FileResponse后删除文件报PermissionError: [WinError 32]

在temp文件夹生成video.mp4作为附件发送给用户后删除,但执行os.remove(file_path)时返回PermissionError: [WinError 32],是否是删除过早导致?相关代码如下:

def download_video(request):
    if request.method == 'POST':
        link_input_data = request.POST.get('link_input_field')  # todo change to use django forms later
        download_cda.start_download(link_input_data)
        file_path = "temp\\" + "video.mp4"
        response = None
        try:
            file = open(file_path, "rb")
            response = FileResponse(file, as_attachment=True, filename="video.mp4")
        except Exception as e:
            print(e)  # todo add exception code
        finally:
            os.remove(file_path)
        return response
    else:
        form = UrlForm()
        return render(request, 'index.html', {"url_form": form})

原因分析

就是删除时机过早:

  • FileResponse采用流式传输,不会立即把整个文件读入内存并发送给客户端,而是在后续响应处理过程中逐步读取文件内容。你在finally块里调用os.remove时,文件还被打开的file句柄占用,同时Django的响应流程还在依赖这个文件,Windows系统会因为文件被进程占用而拒绝删除操作(WinError32对应“文件正在被另一个进程使用,无法访问”)。
  • 代码中直接open文件但没有手动关闭句柄,进一步加剧了文件被占用的情况。

解决方法

方案1:利用响应回调延迟删除(适合大文件)

通过add_post_render_callback让文件在响应完全发送给客户端后再删除,此时文件已不再被占用:

def download_video(request):
    if request.method == 'POST':
        link_input_data = request.POST.get('link_input_field')
        download_cda.start_download(link_input_data)
        file_path = "temp\\video.mp4"
        try:
            # 使用with上下文管理器自动关闭文件句柄
            with open(file_path, "rb") as file:
                response = FileResponse(file, as_attachment=True, filename="video.mp4")
                # 定义回调函数,响应完成后删除文件
                def delete_file(response):
                    os.remove(file_path)
                response.add_post_render_callback(delete_file)
        except Exception as e:
            print(e)
            return HttpResponse("文件处理出错", status=500)
        return response
    else:
        form = UrlForm()
        return render(request, 'index.html', {"url_form": form})

方案2:读取文件到内存后删除(适合小文件)

把文件内容全部读入内存,再删除原文件,最后返回内存中的内容:

def download_video(request):
    if request.method == 'POST':
        link_input_data = request.POST.get('link_input_field')
        download_cda.start_download(link_input_data)
        file_path = "temp\\video.mp4"
        response = None
        try:
            with open(file_path, "rb") as file:
                file_content = file.read()
            # 文件已读入内存,此时可以安全删除
            os.remove(file_path)
            response = HttpResponse(file_content, content_type='video/mp4')
            response['Content-Disposition'] = 'attachment; filename="video.mp4"'
        except Exception as e:
            print(e)
            return HttpResponse("文件处理出错", status=500)
        return response
    else:
        form = UrlForm()
        return render(request, 'index.html', {"url_form": form})

注意:此方法不适合大文件,会占用过多内存。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 19:12:33