Django使用FileResponse返回文件后删除报错WinError32如何解决?
问题本质
该PermissionError触发的核心原因是Django的FileResponse属于流式响应,视图return响应对象时仅完成响应初始化,尚未开始向客户端发送文件内容,此时传给FileResponse的文件句柄仍处于占用状态,直接在视图finally块执行删除操作会触发操作系统的文件占用锁限制,添加sleep无法根治,因为响应发送时长不固定。
解决方案
方案1:绑定清理逻辑到响应关闭回调
Django会在响应完全发送完成后自动调用FileResponse的close方法,可将文件删除逻辑绑定到这个回调上,确保只有文件被读取完、句柄关闭后再执行删除:
from rest_framework import views, status from django.http import FileResponse import os class DownloadShoppingCartView(views.APIView): def get(self, request): file_path = 'test.txt' try: with open(file_path, 'w+') as file: file.write('supertest\n') f = open(file_path, mode='rb') response = FileResponse( f, as_attachment=True, status=status.HTTP_200_OK ) # 绑定清理逻辑 original_close = response.close def close_with_cleanup(): original_close() f.close() if os.path.exists(file_path): os.remove(file_path) response.close = close_with_cleanup return response except Exception as e: # 异常场景也要清理文件 if os.path.exists(file_path): os.remove(file_path) print('自定义异常处理逻辑')
方案2:使用Django封装的临时文件(推荐临时文件场景)
如果文件属于下载用的临时文件,直接使用django.core.files.temp.NamedTemporaryFile即可,Django对该类做了流式响应适配,会在响应发送完成后自动清理文件,无需手动写删除逻辑,同时天然适配Windows和Linux平台的文件锁规则:
from rest_framework import views, status from django.http import FileResponse from django.core.files.temp import NamedTemporaryFile class DownloadShoppingCartView(views.APIView): def get(self, request): try: # delete=False适配Windows平台,避免文件被提前删除 temp_file = NamedTemporaryFile(mode='w+', suffix='.txt', delete=False) temp_file.write('supertest\n') temp_file.close() return FileResponse( open(temp_file.name, mode='rb'), as_attachment=True, filename='shopping_cart.txt', status=status.HTTP_200_OK ) except Exception as e: print('自定义异常处理逻辑')
直接使用标准库tempfile未生效的原因是标准库临时文件默认关闭即自动删除,而FileResponse读取文件是在视图return之后执行,会出现文件已经被删除、或者删除时被占用的问题。
内容的提问来源于stack exchange,提问作者JohnShallow
相关产品推荐
相关产品推荐

