I'm trying to upload a simple text file and then display it in another URL in flask. However, I'm getting a blank output with b" as the only thing showing. Its just a regular text file with utf-8.
Here's the code -
def upload_source():
if request.method == 'POST':
# check if the post request has the file part
f = request.files['file']
if f.filename == "":
print("No file Name")
return redirect(request.url)
if not allowed_file(f.filename):
print("File extension not allowed!")
return redirect(request.url)
else:
full_filename = secure_filename(f.filename)
f.save(os.path.join(app.config['UPLOAD_FOLDER'], full_filename))
print("File saved")
content = f.read()
return render_template('source.html', text=content)
and i'm including this in the source html
<p> {{ text }} </p>
I'm relatively new to python and flask and I appreciate your help here. Thank you!
Thanks to the commenters on this post, I could come up with a fix to this. Initially, I was getting a b" as the only output after using only f.read().
When I used f.seek(0), I got the output of my text file but with a lot of encoding and formatting errors, including a new preceding b` followed by my output.
But adding content = f.read()
content = str(content, 'utf-8') fixed most of that aswell.
So here goes the final solution-
def upload_source():
if request.method == 'POST':
# check if the post request has the file part
f = request.files['file']
if f.filename == "":
print("No file Name")
return redirect(request.url)
if not allowed_file(f.filename):
print("File extension not allowed!")
return redirect(request.url)
else:
full_filename = secure_filename(f.filename)
f.save(os.path.join(app.config['UPLOAD_FOLDER'], full_filename))
f.seek(0)
print("File saved")
content = f.read()
content = str(content, 'utf-8')
return render_template('source.html', text=content)
and don't forget the same old HTML -
<p> {{ text }} </p>
I hope this can help others as well. Thank you!
Related
I am writing my first flask application. I am dealing with file uploads, and basically what I want is to read the data/content of the uploaded file without saving it and then print it on the resulting page. Yes, I am assuming that the user uploads a text file always.
Here is the simple upload function i am using:
#app.route('/upload/', methods=['GET', 'POST'])
def upload():
if request.method == 'POST':
file = request.files['file']
if file:
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
a = 'file uploaded'
return render_template('upload.html', data = a)
Right now, I am saving the file, but what I need is that 'a' variable to contain the content/data of the file .. any ideas?
FileStorage contains stream field. This object must extend IO or file object, so it must contain read and other similar methods. FileStorage also extend stream field object attributes, so you can just use file.read() instead file.stream.read(). Also you can use save argument with dst parameter as StringIO or other IO or file object to copy FileStorage.stream to another IO or file object.
See documentation: http://flask.pocoo.org/docs/api/#flask.Request.files and http://werkzeug.pocoo.org/docs/datastructures/#werkzeug.datastructures.FileStorage.
If you want to use standard Flask stuff - there's no way to avoid saving a temporary file if the uploaded file size is > 500kb. If it's smaller than 500kb - it will use "BytesIO", which stores the file content in memory, and if it's more than 500kb - it stores the contents in TemporaryFile() (as stated in the werkzeug documentation). In both cases your script will block until the entirety of uploaded file is received.
The easiest way to work around this that I have found is:
1) Create your own file-like IO class where you do all the processing of the incoming data
2) In your script, override Request class with your own:
class MyRequest( Request ):
def _get_file_stream( self, total_content_length, content_type, filename=None, content_length=None ):
return MyAwesomeIO( filename, 'w' )
3) Replace Flask's request_class with your own:
app.request_class = MyRequest
4) Go have some beer :)
I share my solution (assuming everything is already configured to connect to google bucket in flask)
from google.cloud import storage
#app.route('/upload/', methods=['POST'])
def upload():
if request.method == 'POST':
# FileStorage object wrapper
file = request.files["file"]
if file:
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = app.config['GOOGLE_APPLICATION_CREDENTIALS']
bucket_name = "bucket_name"
storage_client = storage.Client()
bucket = storage_client.bucket(bucket_name)
# Upload file to Google Bucket
blob = bucket.blob(file.filename)
blob.upload_from_string(file.read())
My post
Direct to Google Bucket in flask
I was trying to do the exact same thing, open a text file (a CSV for Pandas actually). Don't want to make a copy of it, just want to open it. The form-WTF has a nice file browser, but then it opens the file and makes a temporary file, which it presents as a memory stream. With a little work under the hood,
form = UploadForm()
if form.validate_on_submit():
filename = secure_filename(form.fileContents.data.filename)
filestream = form.fileContents.data
filestream.seek(0)
ef = pd.read_csv( filestream )
sr = pd.DataFrame(ef)
return render_template('dataframe.html',tables=[sr.to_html(justify='center, classes='table table-bordered table-hover')],titles = [filename], form=form)
I share my solution, using pandas
#app.route('/upload/', methods=['POST'])
def upload():
if request.method == 'POST':
# FileStorage object wrapper
file = request.files["file"]
if file:
df = pd.read_excel(files_excel["file"])
Building on a great answer by #tbicr the simplest form of that boils down to:
for line in request.files.get('file'):
print("Next line: " + line)
in function
def handleUpload():
if 'photo' in request.files:
photo = request.files['photo']
if photo.filename != '':
image = request.files['photo']
image_string = base64.b64encode(image.read())
image_string = image_string.decode('utf-8')
#use this to remove b'...' to get raw string
return render_template('handleUpload.html',filestring = image_string)
return render_template('upload.html')
in html file
<html>
<head>
<title>Simple file upload using Python Flask</title>
</head>
<body>
{% if filestring %}
<h1>Raw image:</h1>
<h1>{{filestring}}</h1>
<img src="data:image/png;base64, {{filestring}}" alt="alternate" />.
{% else %}
<h1></h1>
{% endif %}
</body>
In case we want to dump the in memory file to disk. This code can be used
if isinstanceof(obj,SpooledTemporaryFile):
obj.rollover()
I trying to delete a file I've created after it was displayed on the webservice.
However with the current placement of the function, it says 'remove_file(response) is not accessed' and when I run the webservice I get an error when outputting the file, as it apparently already has been deleted.
I don't know what to do anymore, I've tried placing the afer_this_request function right after the upload_file declaration, after the return render template, all of it never works. I'm going crazy, so any help would make my year!
#app.route('/', methods=['POST', 'GET'])
def upload_file():
if request.method == 'POST':
myuuid = uuid.uuid4()
# check if the post request has the file part
if 'file' not in request.files:
return render_template('error.html')
file = request.files['file']
# If the user does not select a file, the browser submits an
# empty file without a filename.
if file.filename == '':
return render_template('error.html')
if file and allowed_file(file.filename):
sfilename = secure_filename(file.filename)
if not os.path.exists(app.config['UPLOAD_FOLDER']):
os.mkdir(app.config['UPLOAD_FOLDER'])
output_path = os.path.join(app.config['UPLOAD_FOLDER'], sfilename)
file.save(output_path)
if 'Alpha Miner' in request.form:
Alpha(pro_file, myuuid)
img_url = url_for('static', filename=str(myuuid) + '.gv.svg')
#after_this_request
def remove_file(response):
os.remove(img_url)
return response
titel = "Petri Net for Alpha Miner: " + sfilename
return render_template('upload.html', img_url=img_url, titel = title)
Try this :
file_handle = open(img_url, 'r')
#after_this_request
def remove_file(response):
try:
os.remove(img_url)
file_handle.close()
except Exception as error:
app.logger.error("Error removing or closing downloaded file handle", error)
return response
I have a project which allows users to upload files, they will eventually get processed and then serve a result file.
I've just realised, now that I am trying to implement the processing part of the system, that the files are empty when uploaded and I'm not sure where this is going wrong. The files are successfully named and put in the directories, but are empty.
Any help would be much appreciated.
The html form for uploads:
<div class="tile is-vertical is-parent coach" id='fileUploadTile'>
<div class="tile is-child box has-background-light">
<form action='/' method='POST' enctype="multipart/form-data">
<div class='drop-zone'>
<span class='drop-zone__prompt is-family-monospace'>Drag and drop or click here to upload files</span>
<input class="drop-zone__input" type="file" multiple name="uploaded_file" id='fileLoader'>
</div> <!-- end of drop-zone-->
<div class='buttons are-medium' id='fileButtons'>
<input type='submit' class="button is-success is-light is-outlined is-family-monospace" id='submitFiles' value='Process file(s)'>
</form>
<button class='button is-danger is-light is-outlined is-family-monospace' name='resetFiles' id='resetFiles'>Reset File(s)</button>
</div> <!-- end of buttons -->
</div> <!-- end of tile is-child -->
</div> <!-- end of tile is-vertical -->
The code which attempts to validate the files (check extensions, file size, name, etc) and then save:
def file_upload():
if session:
session_name = session.get('public_user')
print("New request from " + str(session_name))
# update when last request was sent
active_sessions[session_name] = datetime.now()
else:
session_token = generate_session_token()
print("Generating new session... " + session_token)
session['public_user'] = session_token # session = key, last request = value
active_sessions[session_token] = datetime.now()
os.mkdir('uploads/'+session['public_user']) #create directory for uploaded files
if request.method == "POST":
if request.files:
files_processed = True
files = request.files.getlist("uploaded_file")
upload_path = app.config['UPLOAD_FOLDER'] + \
str(session['public_user'])
# loop, as possibility of multiple file uploads
for file_to_upload in files:
file_to_upload.seek(0, os.SEEK_END)
file_length = file_to_upload.tell()
file_name = check_existing_file_name(file_to_upload.filename)
# Secures file name against user input
file_name = secure_filename(file_name)
# Checks the file name isn't blank
if file_to_upload.filename == "":
print("Error with file" + file_to_upload.filename +
" - name must not be blank")
files_processed = False
continue
# Checks the file has an allowed extension
elif not allowed_ext(file_to_upload.filename):
print("Error with file" + file_to_upload.filename +
" - extension not supported")
files_processed = False
continue
# Checks file size
elif file_length > app.config['MAX_FILE_SIZE']:
print("Error with file" +
file_to_upload.filename + " file too big")
files_processed = False
continue
else: # Else, passes all validation and is saved.
file_path = upload_path + "/" + file_name
file_to_upload.save(file_path)
# If files have been processed, return a render with success message
if files_processed is True:
return render_template('index.html', is_home='yes', succ="Now processing your files...")
else: # Else, normal redirect.
return redirect(request.url)
else: # If no files request, redirect to index.
return redirect(request.url)
else: # If not a POST request, load page as normal.
return render_template('index.html', is_home='yes')
Sorry if this is something easy or silly I've missed - this is my first project in Python and my first time using Flask.
This all looks pretty ok.
Unrelated: I would do the check for the empty file name against file_name - not file_to_upload.filename.
About your problem:
The only sensible answer could be that with any of your many actions you put the file pointer at the end of the file, and save cannot handle it.
Unfortunately, I have no time to try this on my pc, so please do a seek 0 again - this time just before you call the save method.
I will try this later and update my answer accordingly.
Another way to find out what is going is using a debugger. That is not too complicated.
I made a 5 min video - just for debugging Flask: https://www.youtube.com/watch?v=DB4peJ1Lm2M
I was having the same issue and the recommended fix above helped me! From what I understand it is because you file pointer at the end of the file when you grab the file size. This just has to be undone with another file_to_upload.seek(0).
Just for clarity, your code should now look like:
file_path = upload_path + "/" + file_name
file_to_upload.seek(0)
file_to_upload.save(file_path)
I have from and in the form the user can upload files.
I'm using flask, and what im trying to do is to get the data from the text file that the user choose to upload.
There is any way to read the data inside the text file?
I have tried to open the file file = open(), but then i realized that i dont have the path.
Its diffrent then reading file on your local machine.
#app.route('/admin',methods=['GET','POST'])
def admin_panel():
if request.method == 'GET':
return render_template('adminpanel.html')
if request.method == 'POST':
email = request.form['email']
file_data = request.files['file']
file_name = secure_filename(file_data.filename)
file_data.save(os.path.join("system","files","text",file_name))
with open("system/files/text/file_name") as f:
file_content = f.read()
print(file_content)
file = File(file_data)
file.read_file_dif()
Well of course this code does not working. But thats the idea.
Anyone have any idea how i can read a text file from an input file tag?
HTML TAG
<label for="myfile">Select a file:</label>
<input type="file" id="myfile" name="file">
The best way to approach is first saving the file and then reading it to get the text. As a convention, you set a UPLOAD_FOLDER variable with the path to save. Then, in flask use the following to save the file:
file_path = os.path.join(app.config['UPLOAD_FOLDER'], secure_filename(f.filename))
f = request.files['file']
f.save(file_path)
# This would save the file. Now to read simply use the normal way to read files in Python
with open(file_path, 'r') as f:
file_content = f.read()
# Rest of the processing logic
Note that the path is relative to your current working directory, which is usually the root of your project. Also, please be careful when storing and reading files from untrusted users.
A better place to store these files would be somewhere other than your project root. You could have a data directory somewhere through which you could configure Nginx (or any other front proxy) to serve the uploaded files
This is my solution to my problem
from werkzeug.utils import secure_filename
import os
class File():
def __init__(self,file):
self.file = file
def read_file(self):
file_name = secure_filename(self.file.filename)
self.file.save(os.path.join("app", "static", file_name))
with open(f"app/static/{file_name}") as f:
email_list = f.read().splitlines()
return email_list
If user doesn't select a file in form (equals PHP UPLOAD_ERR_NO_FILE
), request.files['file'] also return a FileStorage object, I am using request.files['file'].filename == '' to check, any better way ? I have seen Flask Doc but can't find the answer.
'file' in request.files will not work on user doesn't select file, browser also will submit a 0 length and filename equals '' (empty string) part.
and how do I detect uploaded file was only partially uploaded error (equals PHP UPLOAD_ERR_PARTIAL) ?
Now I am using
if request.files['file'].filename == '':
return 'No selected file'
or using file length check
import os
file = request.files['file']
file.seek(0, os.SEEK_END)
if file.tell() == 0:
return 'No selected file'
Try:
if not request.files.get('file', None):
pass
If you want have most control over the files, you can use http://pythonhosted.org/Flask-Uploads/
import imghdr
def validate_image(stream):
header = stream.read(512)
stream.seek(0)
format = imghdr.what(None, header)
if not format:
return None
return '.'+format
class UploadFiles(Resource):
def post(self):
doc=request.files.get('image')
if validate_image(doc.stream):
print('file validated')