Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a temporary compressed file

Tags:

python

I need to create a temporary file to send it, I have tried :

# Create a temporary file --> I think it is ok (file not seen)
temporaryfile = NamedTemporaryFile(delete=False, dir=COMPRESSED_ROOT)

# The path to archive --> It's ok
root_dir = "something"

# Create a compressed file --> It bugs
data = open(f.write(make_archive(f.name, 'zip', root_dir))).read()

# Send the file --> Its ok
response = HttpResponse(data, mimetype='application/zip')
response['Content-Disposition'] = 'attachment; filename="%s"' % unicode(downloadedassignment.name + '.zip')
return response

I don't know at all if it is the good approach..

like image 984
nlassaux Avatar asked Aug 15 '12 10:08

nlassaux


People also ask

What are examples of temporary files?

For example, Microsoft Windows and Windows programs often create a file with a . tmp file extension as a temporary file. Programs like Microsoft Word may create a temporary hidden file beginning with a tilde and a dollar sign (e.g., ~$example. doc) in the same directory as the document.

What are temporary program files?

A temporary program file (TMP) is made by a computer program for a variety of purposes. Generally, a TMP file is made to temporarily store data while a new file or process is being made.


2 Answers

I actually just needed to do something similar and I wanted to avoid file I/O entirely, if possible. Here's what I came up with:

import tempfile
import zipfile

with tempfile.SpooledTemporaryFile() as tmp:
    with zipfile.ZipFile(tmp, 'w', zipfile.ZIP_DEFLATED) as archive:
        archive.writestr('something.txt', 'Some Content Here')

    # Reset file pointer
    tmp.seek(0)

    # Write file data to response
    return HttpResponse(tmp.read(), mimetype='application/x-zip-compressed')

It uses a SpooledTemporaryFile so it will remain in-memory, unless it exceeds the memory limits. Then, I set this tempory file as the stream for ZipFile to use. The filename passed to writestr is just the filename that the file will have inside the archive, it doesn't have anything to do with the server's filesystem. Then, I just need to rewind the file pointer (seek(0)) after ZipFile had done its thing and dump it to the response.

like image 94
Chris Pratt Avatar answered Oct 19 '22 04:10

Chris Pratt


First of all, you don't need to create a NamedTemporaryFile to use make_archive; all you want is a unique filename for the make_archive file to create.

.write doesn't return a filename

To focus on that error: You are assuming that the return value of f.write is a filename you can open; just seek to the start of your file and read instead:

f.write(make_archive(f.name, 'zip', root_dir))
f.seek(0)
data = f.read()

Note that you'll also need to clean up the temporary file you created (you set delete=False):

import os
f.close()
os.unlink(f.name)

Alternatively, just omit the delete keyword to have it default to True again and only close your file afterwards, no need to unlink.

That just wrote the archive filename to a new file..

You are just writing the new archive name to your temporary file. You'd be better off just reading the archive directly:

data = open(make_archive(f.name, 'zip', root_dir), 'rb').read()

Note that now your temporary file isn't being written to at all.

Best way to do this

Avoid creating a NamedTemporaryFile altogether: Use tempfile.mkdtemp() instead, to generate a temporary directory in which to put your archive, then clean that up afterwards:

tmpdir = tempfile.mkdtemp()
try:
    tmparchive = os.path.join(tmpdir, 'archive')

    root_dir = "something"

    data = open(make_archive(tmparchive, 'zip', root_dir), 'rb').read()

finally:
    shutil.rmtree(tmpdir)
like image 38
Martijn Pieters Avatar answered Oct 19 '22 04:10

Martijn Pieters