使用来自 Flask 的 send_file() 时文件损坏,来自 pymongo gridfs 的数据
File corrupted when using send_file() from flask, data from pymongo gridfs
我的英语不好,标题可能看起来很奇怪。
反正我现在正在用flask搭建一个可以存储文件的网站,mongodb就是数据库
文件上传,文档插入功能没有问题,奇怪的是从flask send_file()
发送的文件被无故截断了。这是我的代码
from flask import ..., send_file, ...
import pymongo
import gridfs
#...
@app.route("/record/download/<record_id>")
def api_softwares_record_download(record_id):
try:
#...
file = files_gridfs.find_one({"_id": record_id})
file_ext = filetype.guess_extension(file.read(2048))
filename = "{}-{}{}".format(
app["name"],
record["version"],
".{}".format(file_ext) if file_ext else "",
)
response = send_file(file, as_attachment=True, attachment_filename=filename)
return response
except ...
例如,原始图像文件为553KB。但是响应 body returns 549.61KB,并且图像被破坏了。但是如果我直接把文件写到我的磁盘
#...
with open('test.png', 'wb+') as file:
file.write(files_gridfs.find_one({"_id": record_id}).read())
图片文件大小为553KB,图片可读。
当我用 VS Code 的文本编辑器比较这两个文件时,我发现正确的文件以 �PNG
开头,但损坏的文件以 �ϟ8���>�L�y
开头
search the corrupted file head in the correct file
我尝试使用 Blob
object 从浏览器下载。没有区别。
是我的代码有问题还是我用错了send_file()
?或者我应该使用 flask_pymongo
?
有趣的是,我发现我的代码有什么问题。
我就是这样解决的
...file.read(2048)
file.seek(0)
...
file.read(2048)
file.seek(0)
...
response = send_file(file, ...)
return response
原因如下:
由于某些原因,我使用filetype
来检测文件的扩展名和mime类型,所以我将2048B发送给filetype
进行检测。
file_ext = filetype.guess_extension(file.read(2048))
file_mime = filetype.guess_mime(file.read(2048)) #this line wasn't copied in my question. My fault.
而且我刚刚从pymongo API了解到python(或pymongo
或gridfs
,之前完全不知道)使用游标读取文件。当我尝试使用 file.seek()
查找光标的位置时,它 returns 4096
。所以当我在send_file()
中再次调用file.read()
时,光标从4096B读取到文件头。 549+4=553,问题来了
最后,我在每次 read()
操作后将光标设置到位置 0,它 returns 是正确的文件。
如果你和我一样犯了同样的错误,希望这对你有所帮助。
我的英语不好,标题可能看起来很奇怪。
反正我现在正在用flask搭建一个可以存储文件的网站,mongodb就是数据库
文件上传,文档插入功能没有问题,奇怪的是从flask send_file()
发送的文件被无故截断了。这是我的代码
from flask import ..., send_file, ...
import pymongo
import gridfs
#...
@app.route("/record/download/<record_id>")
def api_softwares_record_download(record_id):
try:
#...
file = files_gridfs.find_one({"_id": record_id})
file_ext = filetype.guess_extension(file.read(2048))
filename = "{}-{}{}".format(
app["name"],
record["version"],
".{}".format(file_ext) if file_ext else "",
)
response = send_file(file, as_attachment=True, attachment_filename=filename)
return response
except ...
例如,原始图像文件为553KB。但是响应 body returns 549.61KB,并且图像被破坏了。但是如果我直接把文件写到我的磁盘
#...
with open('test.png', 'wb+') as file:
file.write(files_gridfs.find_one({"_id": record_id}).read())
图片文件大小为553KB,图片可读。
当我用 VS Code 的文本编辑器比较这两个文件时,我发现正确的文件以 �PNG
开头,但损坏的文件以 �ϟ8���>�L�y
search the corrupted file head in the correct file
我尝试使用 Blob
object 从浏览器下载。没有区别。
是我的代码有问题还是我用错了send_file()
?或者我应该使用 flask_pymongo
?
有趣的是,我发现我的代码有什么问题。
我就是这样解决的
...file.read(2048)
file.seek(0)
...
file.read(2048)
file.seek(0)
...
response = send_file(file, ...)
return response
原因如下:
由于某些原因,我使用filetype
来检测文件的扩展名和mime类型,所以我将2048B发送给filetype
进行检测。
file_ext = filetype.guess_extension(file.read(2048))
file_mime = filetype.guess_mime(file.read(2048)) #this line wasn't copied in my question. My fault.
而且我刚刚从pymongo API了解到python(或pymongo
或gridfs
,之前完全不知道)使用游标读取文件。当我尝试使用 file.seek()
查找光标的位置时,它 returns 4096
。所以当我在send_file()
中再次调用file.read()
时,光标从4096B读取到文件头。 549+4=553,问题来了
最后,我在每次 read()
操作后将光标设置到位置 0,它 returns 是正确的文件。
如果你和我一样犯了同样的错误,希望这对你有所帮助。