Skip to content

Instantly share code, notes, and snippets.

@boris317
Created September 10, 2012 20:57
Show Gist options
  • Save boris317/3693796 to your computer and use it in GitHub Desktop.
Save boris317/3693796 to your computer and use it in GitHub Desktop.
Stream a tar file with flask.
import os
from cStringIO import StringIO
import tarfile
from flask import Flask, Response
app = Flask(__name__)
def get_string_io_len(s):
pos = s.tell()
s.seek(0, os.SEEK_END)
length = s.tell()
s.seek(pos)
return length
class CrazyBuffer(object):
def __init__(self):
self._buffer = StringIO()
def read(self, nbytes=None):
pass
def write(self, data):
self._buffer.write(data)
def close(self):
pass
def tell(self):
return 0
def seek(self, offset, whence=None):
return 0
def get_value(self):
return self._buffer.getvalue()
def reset(self):
self._buffer.close()
self._buffer = StringIO()
def streamed_tar_response(files):
crazy_buffer = CrazyBuffer()
tar = tarfile.open("test.tar", "w", crazy_buffer)
for i, f in enumerate(files):
info = tarfile.TarInfo(name="File_%s.txt" % i)
#stringIO specific here
info.size = get_string_io_len(f)
tar.addfile(info, f)
yield crazy_buffer.get_value()
crazy_buffer.reset()
# Making shit up at this point in case there
# is someting in the buffer after the loop.
# Not sure if actually needed!
tar.close()
yield crazy_buffer.get_value()
@app.route("/tar", methods=["GET"])
def get_tar():
files = [
StringIO("I am file 1."),
StringIO("I am file 2.")
]
return Response(streamed_tar_response(files), mimetype="application/x-tar")
if __name__ == "__main__":
app.run()
@Gu-f
Copy link

Gu-f commented Apr 3, 2023

Oh wait my bad. It's not as bad as I thought. As each file is added, it's read into memory and then sent to the client as a whole. Fine if all your files are small, but not what I'm looking for.

I had the same problem. What's your solution?

@ioistired
Copy link

ioistired commented Apr 3, 2023 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment