【问题标题】:How do I deal with the uploaded file data manually?如何手动处理上传的文件数据?
【发布时间】:2019-12-20 08:15:58
【问题描述】:

我正在尝试手动保存上传的文件以供学习,没有request.files 的帮助。

我正在使用 Flask,它为我提供了 str 类型的原始身体数据,print(type(reqeust.data))

  1. 我很困惑。我不应该得到二进制数据<type bytes> 吗?

但后来我又想,即使我得到二进制数据,如何过滤前几行,然后从正确的地方开始读取二进制数据?

例如:

-----------------------------1699415032232102060211780227
Content-Disposition: form-data; name="myfile"; filename="Screenshot from 2018-10-05 15-49-07.png"
Content-Type: image/png

�PNG

�ߧd�tEXtSoftwaregnome-screenshot��>�IDATx���OPY����l�*c���=��El"f[��)3��S�+z-v�0�c������zp����6��qS�\W��6S�qM�S=tG�Ǩb��A�ؒvc���@rh��.N]���?JK����b+�J��(�����OR�T
-----------------------------1699415032232102060211780227--

  1. 谁能教我如何手动保存文件数据?

【问题讨论】:

  • 我不明白您所说的“手动”是什么意思?
  • @roganjosh 使用 python 文件输入/输出函数检索 (PNG) 文件数据并将其保存在服务器上。
  • 那么,不使用.save() 就像this 一样?你想解决什么问题?
  • @roganjosh 是的,不使用框架提供的save()。我只想知道如何像save() 那样手动保存文件。
  • save 方法是 [这里]((github.com/pallets/werkzeug/blob/master/src/werkzeug/…)),所以你可以拼凑它经历的过程

标签: python flask


【解决方案1】:

最后我自己弄明白了。

  1. 我之所以从request.data 获得str 是因为我使用的是python2.7 烧瓶包。真是让人头疼。下次我肯定会使用virtualenv,即使是用于测试。但是我还是不明白为什么我可以在服务端代码中使用python3语法,而包与python2.7相关。

  2. 所以实际上我从request.data 获取了像b'raw binary data' 这样的原始字节数据。以及来自其他功能的数据,例如比如request.form['firstname']已经被解码了。

所以现在问题归结为我如何重建文件,提供二进制数据。


首先,我准备了 2 个小文件进行测试。

文件1:1.txt

内容:1234567

file2: test.png这个小图片 ------>

内容(使用open('test.png', 'rb').read()):

b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\t\x00\x00\x00\x08\x08\x02\x00\x00\x00\xa4\xafB\xe2\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\x00\x00\x00\x10tEXtSoftware\x00Shutterc\x82\xd0\t\x00\x00\x00\x15IDAT\x08\xd7c\xd4\xe5Tb\xc0\x01\x98\x18p\x83\xa1"\x07\x00T;\x00h\xb9\x9335\x00\x00\x00\x00IEND\xaeB`\x82'

所以我在服务器上看到的request.data是:

b'-----------------------------16866548741414816351605255076\r\nContent-Disposition: form-data; name="myfile"; filename="1.txt"\r\nContent-Type: text/plain\r\n\r\n1234567\r\n-----------------------------16866548741414816351605255076\r\nContent-Disposition: form-data; name="myfile2"; filename="test.png"\r\nContent-Type: image/png\r\n\r\n\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\t\x00\x00\x00\x08\x08\x02\x00\x00\x00\xa4\xafB\xe2\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\x00\x00\x00\x10tEXtSoftware\x00Shutterc\x82\xd0\t\x00\x00\x00\x15IDAT\x08\xd7c\xd4\xe5Tb\xc0\x01\x98\x18p\x83\xa1"\x07\x00T;\x00h\xb9\x9335\x00\x00\x00\x00IEND\xaeB`\x82\r\n-----------------------------16866548741414816351605255076--\r\n'

稍微格式化一下:

(数据不能直接使用,因为我添加了额外的新行用于显示。)

b'-----------------------------16866548741414816351605255076\r\n  
Content-Disposition: form-data; name="myfile"; filename="1.txt"\r\n
Content-Type: text/plain\r\n\r\n
1234567\r\n
  -----------------------------16866548741414816351605255076\r\n 
Content-Disposition: form-data; name="myfile2"; filename="test.png"\r\n
Content-Type: image/png\r\n\r\n
\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\t\x00\x00\x00\x08\x08\x02\x00\x00\x00\xa4\xafB\xe2\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\x00\x00\x00\x10tEXtSoftware\x00Shutterc\x82\xd0\t\x00\x00\x00\x15IDAT\x08\xd7c\xd4\xe5Tb\xc0\x01\x98\x18p\x83\xa1"\x07\x00T;\x00h\xb9\x9335\x00\x00\x00\x00IEND\xaeB`\x82\r\n
-----------------------------16866548741414816351605255076--\r\n'

raw_data = binary data above

  1. files_data_array = raw_data.split(b'-----------------------------16866548741414816351605255076\r\n)

然后我得到一个数组,每个文件在不同的索引中。

这里files_data_array[1] 包含第一个文件元信息和数据。 files_data_array[2] 包含第二个文件元信息和数据。如果您有更多文件,依此类推。

[b'', b'Content-Disposition: form-data; name="myfile"; filename="1.txt"\r\nContent-Type: text/plain\r\n\r\n1234567\r\n', b'Content-Disposition: form-data; name="myfile2"; filename="test.png"\r\nContent-Type: image/png\r\n\r\n\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\t\x00\x00\x00\x08\x08\x02\x00\x00\x00\xa4\xafB\xe2\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\x00\x00\x00\x10tEXtSoftware\x00Shutterc\x82\xd0\t\x00\x00\x00\x15IDAT\x08\xd7c\xd4\xe5Tb\xc0\x01\x98\x18p\x83\xa1"\x07\x00T;\x00h\xb9\x9335\x00\x00\x00\x00IEND\xaeB`\x82\r\n-----------------------------16866548741414816351605255076--\r\n']
  1. file2_data = files_data_array[2]
b'Content-Disposition: form-data; name="myfile2"; filename="test.png"\r\nContent-Type: image/png\r\n\r\n\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\t\x00\x00\x00\x08\x08\x02\x00\x00\x00\xa4\xafB\xe2\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\x00\x00\x00\x10tEXtSoftware\x00Shutterc\x82\xd0\t\x00\x00\x00\x15IDAT\x08\xd7c\xd4\xe5Tb\xc0\x01\x98\x18p\x83\xa1"\x07\x00T;\x00h\xb9\x9335\x00\x00\x00\x00IEND\xaeB`\x82\r\n-----------------------------16866548741414816351605255076--\r\n'

然后按file2_meta_info = file2_data.split(b'\r\n\r\n', maxsplit=1)[0] 拆分元数据。 注意这里我是拆分二进制数据,如果文件数据中有b'\r\n\r\n',需要设置maxsplit

现在我得到file2_meta_infob'Content-Disposition: form-data; name="myfile"; filename="1.txt"',我可以对其进行解码并获得我想要的任何元信息。

现在转到文件正文数据本身,file2_body_data = file2_data.split(b'\r\n\r\n', maxsplit=1)[1]

我明白了

b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\t\x00\x00\x00\x08\x08\x02\x00\x00\x00\xa4\xafB\xe2\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\x00\x00\x00\x10tEXtSoftware\x00Shutterc\x82\xd0\t\x00\x00\x00\x15IDAT\x08\xd7c\xd4\xe5Tb\xc0\x01\x98\x18p\x83\xa1"\x07\x00T;\x00h\xb9\x9335\x00\x00\x00\x00IEND\xaeB`\x82\r\n-----------------------------16866548741414816351605255076--\r\n'

相对于开头显示的test.png的内容,我还是需要删减一些字节

real_file2_body_data = file2_body_data.rsplit(b'\r\n', maxsplit=2)[0]'

最后我可以用 :

重建文件
f = open('test2.png', 'wb')
f.write(real_file2_body_data)
f.close()

完成!

【讨论】:

  • 抱歉变量命名混乱:P。通过重新发明轮子,现在我对引擎盖下发生的事情感到放松。而对于其他不提供b'binary data'.split() 的语言,总是可以使用低级函数来搜索特定字节并进行相同的拆分。
猜你喜欢
  • 2016-02-07
  • 2020-02-23
  • 2010-12-30
  • 1970-01-01
  • 2016-09-08
  • 2010-09-14
  • 2017-02-18
  • 2023-03-20
  • 2018-02-08
相关资源
最近更新 更多