diff --git a/src/flask/__init__.py b/src/flask/__init__.py index 3e7198a6..80c19bb5 100644 --- a/src/flask/__init__.py +++ b/src/flask/__init__.py @@ -25,6 +25,7 @@ from .helpers import get_template_attribute as get_template_attribute from .helpers import make_response as make_response from .helpers import safe_join as safe_join from .helpers import send_file as send_file +from .helpers import send_chunked_file as send_chunked_file from .helpers import send_from_directory as send_from_directory from .helpers import stream_with_context as stream_with_context from .helpers import url_for as url_for diff --git a/src/flask/helpers.py b/src/flask/helpers.py index 7b8b0870..3f99aa2e 100644 --- a/src/flask/helpers.py +++ b/src/flask/helpers.py @@ -626,6 +626,35 @@ def send_file( ) ) +def send_chunked_file(filepath:str , chunk_size: int = 8192): + """ If you serve binary files, you should not iterate through lines since + it basically contains only one line, which means you still load the + whole file all at once into the RAM. The only proper + way to read largit checkout files is via chunks with this function: read_file_chunks(path, chunk_size) + send every chunks with stream_with_context function + :param filepath: file exists there . If not + provided, error occured. + :param chunk_size: defult size is 8192 + """ + name_splited = filepath.split('/') + filename = name_splited[len(name_splited) - 1] + def read_file_chunks(path, chunk_size): + with open(path, 'rb') as fd: + while 1: + buf = fd.read(chunk_size) + if buf: + yield buf + else: + break + if os.path.isfile(filepath): + return current_app.response_class( + stream_with_context(read_file_chunks(filepath, chunk_size)), + headers={ + 'Content-Disposition': f'attachment; filename={filename}' + } + ) + else: + raise NotFound() def safe_join(directory: str, *pathnames: str) -> str: """Safely join zero or more untrusted path components to a base