Vraag fles make_response met grote bestanden


Dus ik ben echt groen met bestands-I / O en geheugenlimieten en dergelijke, en ik heb een moeilijke tijd om mijn webtoepassing succesvol te laten dienen om grote bestandsdownloads naar een webbrowser met flesjes te sturen make_response. De volgende code werkt op kleinere bestanden (<~ 1 GB), maar geeft mij een MemoryError Uitzondering wanneer ik in grotere bestanden stap:

raw_bytes = ""
with open(file_path, 'rb') as r:
    for line in r:
        raw_bytes = raw_bytes + line
response = make_response(raw_bytes)
response.headers['Content-Type'] = "application/octet-stream"
response.headers['Content-Disposition'] = "inline; filename=" + file_name
return response

Ik neem aan dat het overdoen van 2 GB aan binaire gegevens in een string waarschijnlijk een groot nee-nee is, maar ik weet geen alternatief voor het uitvoeren van deze zwarte magicks voor het downloaden van bestanden. Als iemand me op het goede pad zou kunnen brengen met een stevige [?] Of gebufferde aanpak voor het downloaden van bestanden, of me gewoon op een paar middelzware middelen wijzen om een ​​beter begrip van dit spul te faciliteren, zou ik het enorm op prijs stellen. Bedankt!


14
2018-06-20 00:03


oorsprong


antwoorden:


Zie de documentatie op Streaming inhoud. Kortom, je schrijft een functie die stukjes data oplevert, en geeft die generator door aan het antwoord, in plaats van het hele ding tegelijk. Flask en uw webserver doen de rest.

from flask import stream_with_context, Response

@app.route('/stream_data')
def stream_data():
    def generate():
        # create and return your data in small parts here
        for i in xrange(10000):
            yield str(i)

    return Response(stream_with_context(generate()))

Als het bestand statisch is, kunt u in plaats daarvan profiteren van send_from_directory(). De documentatie adviseert u om nginx of een andere server die X-SendFile ondersteunt te gebruiken, zodat het lezen en verzenden van de gegevens efficiënt is.


18
2018-06-20 00:10



Het probleem bij je poging is, dat je eerst volledige inhoud leest in "raw_bytes", dus met grote bestanden kun je gemakkelijk al je geheugen uitputten.

Er zijn meerdere opties om dit op te lossen:

Streaming van de inhoud

Zoals uitgelegd door davidism antwoord, kun je een generator gebruiken die is doorgegeven in Response. Dit dient het grote bestand stuk voor stuk en vereist niet zoveel geheugen.

Het streamen kan niet alleen van een generator komen, maar ook van een bestand, zoals getoond in deze toelichting

Statische bestanden serveren via de kolf

Als uw bestand statisch is, zoekt u naar hoe u Flask configureert voor het weergeven van statische bestanden. Deze worden automatisch op een streamingwijze geserveerd.

Statische bestanden overnemen apache of nginx (of andere webserver)

Ervan uitgaande dat het bestand statisch is, dient u het in productie als reverse-proxy voor uw Flask-app. Dit laadt niet alleen uw app uit, maar werkt ook veel sneller.


2
2018-06-20 00:14