问题
I would like to read all the files in a zip file of a specific type sent to a flask server via a form post request without having to store the zip file on disk.
回答1:
First, get the code to get the zip file
from flask import Flask, request
app = Flask(__name__)
@app.route("/",methods=["GET"])
def page_name_get():
return """<form action="." method="post" enctype=multipart/form-data>
<input type="file" accept="application/zip" name="data_zip_file" accept="application/zip" required>
<button type="submit">Send zip file!</button>
</form>"""
app.run()
This is how the post request function should look like
import zipfile
@app.route("/",methods=["POST"])
def page_name_post():
file = request.files['data_zip_file']
file_like_object = file.stream._file
zipfile_ob = zipfile.ZipFile(file_like_object)
file_names = zipfile_ob.namelist()
# Filter names to only include the filetype that you want:
file_names = [file_name for file_name in file_names if file_name.endswith(".txt")]
files = [(zipfile_ob.open(name).read(),name) for name in file_names]
return str(files)
Now I will go over this line by line
file = request.files['data_zip_file']
First, you need to get the file object from the request this is is an instance of the werkzeug.datastructures.FileStorage
class.
file_like_object = file.stream._file
here you first take the stream attribute of the werkzeug.datastructures.FileStorage
this is the input stream of the file. This will return an instance of tempfile.SpooledTemporaryFile
a class used for temporary files. From that instance, you take the ._file attribute. This will return an instance of tempfile._TemporaryFileWrapper
This is enough like an io.BytesIO
to be understood by the zipfile.ZipFile class.
zipfile_ob = zipfile.ZipFile(file_like_object)
here you create the zipfile.Zipfile
object
Now you should be able to do pretty much everything you would want to do with the zip. To select a file from the zip use the zipfile_ob.open()
method and pass in the path to the file you want to open.
To get those paths we use file_names = zipfile_ob.namelist()
this will return a list with strings of all the paths to all the files and directories in the zip.
You can then filter those names with file_names = [file_name for file_name in file_names if file_name.endswith(".txt")]
All those paths you want are now in file_names
. Then you can extract the data of those files using the open function.
files = [(zipfile_ob.open(name).read(),name) for name in file_names]
In the example given I keep the paths to the file in the final list but if you don't want that you can use:
files = [zipfile_ob.open(name).read() for name in file_names]
or use some other way to go over the file. If you want more info about the files there is also the infolist()
method that can be used instead of the namelist()
this will return a list of ZipInfo Objects instead of a list of just strings. These objects hold some more data about all the files.
来源:https://stackoverflow.com/questions/60643857/read-a-zip-file-sent-to-a-flask-server-without-storing-it-on-disk