I am trying to input a file from an input field, save it temporarily to the disk and reply with a response to re-download the same file.
In order to do this, I've read that I need to reply to the browser with a content-type : application/octet-stream and a content-disposition: attachment; "filename=myfile.extension".
I can store and listen to my music file in the /tmp folder so I know that the input part of it works.
This is my code in Pyramid:
#view_config(route_name='process')
def process_file(request):
input_file = request.POST['file'].file
input_file.seek(0)
file_path = os.path.join('/tmp', '%s.mp3' % uuid.uuid4())
with open(file_path, 'wb') as output_file:
shutil.copyfileobj(input_file, output_file)
print(f"Wrote: {file_path}")
filename = file_path.split('/')[-1]
print(filename)
f = open(file_path, 'rb')
return Response(body_file=f, charset='UTF-8', content_type='application/octet-stream', content_disposition=f'attachment; "filename={filename}"')
These are my response headers:
And this is my response body:
However Chrome/Firefox do not start the download of my binary file. What am I doing wrong?
UPDATE
I also tried with FileResponse from Pyramid without success, I still do not get the download popup.
#view_config(route_name='process')
def process_file(request):
input_file = request.POST['file'].file
input_file.seek(0)
file_path = os.path.join('/tmp', '%s.mp3' % uuid.uuid4())
with open(file_path, 'wb') as output_file:
shutil.copyfileobj(input_file, output_file)
print(f"Wrote: {file_path}")
return FileResponse(file_path, request=request)
Apparently I was thinking how to perform this in the wrong way. I need to return a Response('OK') when I upload the file through /process and make another request to return a FileResponse object, building another endpoint /download and returning that fileresponse object fixed this issue.
Example:
#view_config(route_name='process')
def process_file(request):
input_file = request.POST['file'].file
db = request.POST['volume']
input_file.seek(0)
filename = '%s.mp3' % uuid.uuid4()
file_path = os.path.join('/tmp', filename)
with open(file_path, 'wb') as output_file:
shutil.copyfileobj(input_file, output_file)
if boost_track(file_path, filename, db):
return Response(json_body={'filename': filename})
#view_config(route_name='download')
def download_file(request):
filename = request.GET['filename']
file_path = os.path.join('/tmp', filename)
f = open(file_path, 'rb')
return Response(body_file=f, charset='UTF-8', content_type='application/download', content_disposition=f'attachment; filename="{filename}"')
Related
For the next file info:
[jzun#hscd8a25e93f9vm dates]$ pwd
/home/jzun/vivo_mod_samples/dates
[jzun#hscd8a25e93f9vm dates]$ ls
date_def.json dates_add.rdf dates.bak dates.rdf dates_sub.rdf dates.txt datetime_precision_enum.txt gen_date_rdf.py gen_date_rdf.py.bak gen_dates.py gen_dates.py.bak get.txt README.md run_pump_2_to_create_date_defs.sh sv.cfg
I have the next python2 function:
def read_csv(filename, skip=True, delimiter='|'):
"""
Read a CSV file, return dictionary object
:param filename: name of file to read
:param skip: should lines with invalid number of columns be skipped? False=Throw Exception
:param delimiter: The delimiter for CSV files
:return: Dictionary object
"""
cwd = os.getcwd()
print("read_csv>current dir = " + cwd)
# fp = open(filename, 'rU')
# print(fp)
# data = read_csv_fp(fp, skip, delimiter)
# fp.close()
with open(filename, 'rU') as fp:
data = read_csv_fp(fp, skip, delimiter)
fp.close()
return data
After running it with filename = dates.txt I get the next result:
read_csv>current dir = /home/jzun/vivo_mod_samples/dates
dates.txt file not found
I know similar questions have been posted but interestingly I can not find anything that could help me to solve this problem. Any ideas?
Try passing the full path of the file dates.txt:
cwd = os.getcwd()
file_name = "dates.txt"
file_path = os.path.join(cwd, file_name)
# Double check that file exist
assert os.path.isfile(file_path) is True
with open(file_path, 'rU') as fp:
data = read_csv_fp(fp, skip, delimiter)
fp.close()
import PyPDF2, os, sys, send2trash,pathlib
def encrypt(filename, password):
with open(filename, "rb") as readfile:
reader = PyPDF2.PdfFileReader(readfile)
writer = PyPDF2.PdfFileWriter()
if not reader.isEncrypted:
for page in range(reader.numPages):
writer.addPage(reader.getPage(page))
else:
print(f"{filename} is encrypted")
return None
with open(f"{filename.split('.')[0]}_encrypted.pdf", "wb") as writefile:
writer.encrypt(password)
try:
writer.write(writefile)
except OSError as e:
print(f"File write error {e}")
return None
with open(f"{pathlib.Path(filename).parent}\{pathlib.Path(filename).stem}_encrypted.pdf", "rb") as checkfile:
result = PyPDF2.PdfFileReader(checkfile).decrypt(password)
if result != 0:
try:
send2trash.send2trash(filename)
print(f"file {filename} was deleted after encrypted file verification")
return "Done"
except OSError as e:
print(f"Delete error: {e}, filename: {filename}")
else:
print("Encrypted file %s was not verified so original file %s was not deleted" % (f"{filename.split('.')[0]}_encrypted.pdf", filename))
return None
def decrypt(filename, password):
with open(filename, "rb") as readfile:
reader = PyPDF2.PdfFileReader(readfile)
writer = PyPDF2.PdfFileWriter()
if not reader.isEncrypted:
print(f"{filename} is not_encrypted")
return None
else:
result = reader.decrypt(password)
if result == 0:
print(f"{filename} was not decrypted with password: {password}")
return None
else:
for page in range(reader.numPages):
writer.addPage(reader.getPage(page))
try:
with open(f"{filename}_decrypted.pdf", "wb") as writefile:
writer.write(writefile)
except OSError as e:
print(f"File write error {e}")
return None
return "Done"
# password = sys.argv[1]
# option = sys.argv[2]
password = "test"
option = "decrypt"
if option not in ["encrypt", "decrypt"]:
sys.exit(f"Wrong option, option provided is {option}, supposed to be encrypt or decrypt")
folder_path = os.path.abspath(input("Please enter the path"))
if os.path.exists(folder_path):
for folder, subfolders, files in os.walk(folder_path):
pdfs = filter(lambda x: str(x).lower().endswith(".pdf"), files)
for file in pdfs:
filename = os.path.join(folder, file)
reader = PyPDF2.PdfFileReader(open(filename, "rb"))
encrypt(filename, password) if option == "encrypt" else decrypt(filename, password)
else:
print(f"{folder_path} doesnt exist, exiting")
sys.exit(f"{folder_path} not found")
Hello! The code above doesnt delete the .pdf files with send2trash.
Files seems to be closed, if i copy encrypt function to another file and run it separately - it delete the file provided - no problem. But in this script i get [win32] None errors - it just refuse to delete any file.
Can anyone kindly point at the point i'm missing? Thanks alot !
PS It supposed to go through folder(subfolders), look for .pdf files and encrypt/decrypt them.
Found the issue, sorry :P
reader = PyPDF2.PdfFileReader(open(filename, "rb"))
I am working with an encrypted file, but I can't manage to create a loop with for in order to read it before it get closed and removed.
My intention is to read the data given in the encrypted file and loop it to assign each line to a variable.
Whenever I execute my code, Python just goes straight to finish, without working with the decrypted info; I believe it is because the with command close it before the loop starts.
This is what I want, not working, no errors either:
with open(input_file, 'rb') as fp:
data = fp.read()
fernet = Fernet(key)
encrypted = fernet.decrypt(data)
with tempfile.TemporaryFile() as fp:
fp.write(encrypted)
for url in fp: #Python ignores the tempfile. I belive it is closed in the previous line.
segment = url.strip()
url = 'https://docs.python.org/3.3/tutorial/' + segment
filename = segment + '.html'
filePath = pjoin('Data/' + filename)
response = urlopen(url)
webContent = response.read()
html_content = urlopen(url).read()
matches = re.findall(b'string', html_content);
if len(matches) == 0:
print(segment + ' unchanged.')
else:
with open(filePath, 'wb') as w:
w.write(webContent)
This is the working code (Sorry, tried to make it shorter but couldn't):
with open(input_file, 'rb') as fp:
data = fp.read()
fernet = Fernet(key)
encrypted = fernet.decrypt(data)
with open(output_file, 'wb') as fp:
fp.write(encrypted)
with open(output_file) as fp:
for url in fp:
segment = url.strip()
url = 'https://docs.python.org/3.3/tutorial/' + segment
filename = segment + '.html'
filePath = pjoin('Data/' + filename)
response = urlopen(url)
webContent = response.read()
html_content = urlopen(url).read()
matches = re.findall(b'string', html_content);
if len(matches) == 0:
print(segment + ' unchanged.')
else:
with open(filePath, 'wb') as w:
w.write(webContent)
Header for both examples (apart to make it shorter):
#python 3.6.6
from urllib.request import urlopen
import urllib.request
from os.path import join as pjoin
import re, os, sys, tempfile, six, ctypes, time, fileinput
from cryptography.fernet import Fernet
print("[*] Checking list.dat for consistency . . .")
key = b'wTmVBRLytAmlfkctCuEf59K0LDCXa3sGas3kPg3r4fs=' #Decrypt list.dat
input_file = 'List.dat'
output_file = 'List.txt'
List.txt content:
errors
classes
stdlib
Any hints?
The problem is that once you have written to the file, the "file pointer" is at the end of the file. There's nothing to read.
You can use the seek method to reposition the file pointer at the beginning. Alternatively, closing and re-opening the file (as in your working code) will position the pointer at the beginning of the file.
#LarryLustig pretty much answered why your code wasn't working, but IMO if you eliminate the temp file altogether (which shouldn't be necessary) you don't even need to worry about the cursor. See below commented changes on your desired code.
# We'll use os.linesep to get the line terminator string for your os.
import os
...
with open(input_file, 'rb') as fp:
data = fp.read()
fernet = Fernet(key)
# decode your decrypted bytes into strings. Change 'utf-8' into whichever file encoding you're using if necessary.
decrypted = fernet.decrypt(data).decode('utf-8')
# Don't write to a temp file
# Iterate directly on each line of the extracted data
for url in decrypted.split(os.linesep):
segment = url.strip()
url = 'https://docs.python.org/3.3/tutorial/' + segment
filename = segment + '.html'
filePath = pjoin('Data/' + filename)
response = urlopen(url)
webContent = response.read()
html_content = urlopen(url).read()
matches = re.findall(b'string', html_content);
if len(matches) == 0:
print(segment + ' unchanged.')
else:
with open(filePath, 'wb') as w:
w.write(webContent)
Alternatively, if you know for sure what is the line terminator used in the file (e.g. \r\n, or \n) then you can eliminate using os.linesep altogether.
Here is the link i have used (Download files from Amazon S3 with Django). Using this i'm able to download single file.
Code:
s3_template_path = queryset.values('file')
filename = 'test.pdf'
conn = boto.connect_s3('<aws access key>', '<aws secret key>')
bucket = conn.get_bucket('your_bucket')
s3_file_path = bucket.get_key(s3_template_path)
response_headers = {
'response-content-type': 'application/force-download',
'response-content-disposition':'attachment;filename="%s"'% filename
}
url = s3_file_path.generate_url(60, 'GET',
response_headers=response_headers,
force_http=True)
return HttpResponseRedirect(url)
I need to download multiple files from S3, as a zip would be better. Can the mentioned method be modified and used. If not please suggest other method.
Okay here is a possible solution, it basically downloads each file and zips them into a folder, then returns this to the user.
Not sure if s3_template_path is the same for each file, but change this if neccessary
# python 3
import requests
import os
import zipfile
file_names = ['test.pdf', 'test2.pdf', 'test3.pdf']
# set up zip folder
zip_subdir = "download_folder"
zip_filename = zip_subdir + ".zip"
byte_stream = io.BytesIO()
zf = zipfile.ZipFile(byte_stream, "w")
for filename in file_names:
s3_template_path = queryset.values('file')
conn = boto.connect_s3('<aws access key>', '<aws secret key>')
bucket = conn.get_bucket('your_bucket')
s3_file_path = bucket.get_key(s3_template_path)
response_headers = {
'response-content-type': 'application/force-download',
'response-content-disposition':'attachment;filename="%s"'% filename
}
url = s3_file_path.generate_url(60, 'GET',
response_headers=response_headers,
force_http=True)
# download the file
file_response = requests.get(url)
if file_response.status_code == 200:
# create a copy of the file
f1 = open(filename , 'wb')
f1.write(file_response.content)
f1.close()
# write the file to the zip folder
fdir, fname = os.path.split(filename)
zip_path = os.path.join(zip_subdir, fname)
zf.write(filename, zip_path)
# close the zip folder and return
zf.close()
response = HttpResponse(byte_stream.getvalue(), content_type="application/x-zip-compressed")
response['Content-Disposition'] = 'attachment; filename=%s' % zip_filename
return response
I am using the following code to download my files:
def downloadfile(url): #function to download file
file_name = filename_parse(url)
#print "***********************"
#print "File download started:"
#stime= time.time()
u = urllib2.urlopen(url)
f = open(file_name, 'wb')
getfilesize(u)
file_size = getfilesize(u)
print "Downloading: %s Bytes: %s \n" % (file_name, file_size)
file_size_dl = 0
block_sz = 512
progressbar(u,block_sz,file_size_dl,f,file_size)
f.close()
the thing is that it can download any file exe, txt and others except .pdf files...how can i make it download the pdfs ?
I know this is an old question but for all of those that stumble upon it and are tyring to download the pdf file using python 2 and urllib2 here is the code:
import urllib2
url = 'http://mensenhandel.nl/files/pdftest2.pdf'
print "Download started..."
f = urllib2.urlopen(url)
data = f.read()
with open("test.pdf", "wb") as code:
code.write(data)
print "Download completed..."
Just modify the URL to your needs...
Source: http://www.blog.pythonlibrary.org/2012/06/07/python-101-how-to-download-a-file/