How to download file in streamlit

There are some files generate by my program, I need a button when I press files will be download by my browser, but I don’t know how to do that. could streamlit provide this function?

1 Like

not directly, but there is a workaround. Its discussed in the following contribution: File Download Workaround added to awesome-streamlit.org.

I have created the following function for myself and use it frequently. It works fine for bigger files too, my files often have thousands of rows and so far I haven’t hit a limit yet.

st.markdown(get_table_download_link(df), unsafe_allow_html=True)
def get_table_download_link(df):
    """Generates a link allowing the data in a given panda dataframe to be downloaded
    in:  dataframe
    out: href string
    """
    csv = df.to_csv(index=False)
    b64 = base64.b64encode(csv.encode()).decode()  # some strings <-> bytes conversions necessary here
    href = f'<a href="data:file/csv;base64,{b64}">Download csv file</a>'
4 Likes

Thanks!! Can’t imagine I missed this post :sweat:,I should search more carefully before I post next time

1 Like

hey using that opens a new tab with title about:blank#blocked
and nothing happens

please help

This works for me, just make sure to return href at the bottom of the get_table_download_link function

Heya, this works for me, but the files download without the .csv extension. Is there a way to make sure that the .csv extension occurs or specify the name of the csv file?

Thank you!

I haven’t found a way to do that automatically, but one can always edit the filename to filename.csv when saving the link with the right mouse click.

1 Like

@marciorpcoelho I see, thank you for putting this workaround together it is very useful!

Why did U say that the file is downloaded without the .csv, it’s not true if you have converted your dataframe with the to_csv() method. It’s works like a charm

Adding the ‘download’ tag attribute as shown below allows you to provide a file name and extension.

f'<a href="data:file/csv;base64,{b64}" download="myfilename.csv">Download csv file</a>'

2 Likes

Welcome to the community @dplutchok, and thanks for pointing out the download argument!

1 Like

I’ve been searching for a while, a way to do same thing with excel xlsx file. I finally found
a way to make it work, so I decide to share my code here. I hope it will help someone.

python 3, pandas '0.23.4'

import streamlit as st
import base64
from io import BytesIO

def to_excel(df):
    output = BytesIO()
    writer = pd.ExcelWriter(output, engine='xlsxwriter')
    df.to_excel(writer, sheet_name='Sheet1')
    writer.save()
    processed_data = output.getvalue()
    return processed_data

def get_table_download_link(df):
    """Generates a link allowing the data in a given panda dataframe to be downloaded
    in:  dataframe
    out: href string
    """
    val = to_excel(df)
    b64 = base64.b64encode(val)  # val looks like b'...'
    return f'<a href="data:application/octet-stream;base64,{b64.decode()}" download="extract.xlsx">Download csv file</a>' # decode b'abc' => abc

df = ... # your dataframe
st.markdown(get_table_download_link(df), unsafe_allow_html=True)

# PS: pip install xlsxwriter  # pandas need this
2 Likes

This is a great answer for csv files or excel files.
However does it work on midi (*.mid) files? midi files are binary. like the excel files.

Now I dont think i need to encode/decode to b64. what do you think? if i do use the b64 enc/decoding i get

TypeError: a bytes-like object is required, not '_io.BufferedReader’

if i dont it still doesnt work.
you can find an example midi file here example_midi

example:

import base64
def get_midi_download_link(mid):
    """Generates a link allowing the data in a given midi file to be downloaded
    in:  midi file
    out: href string
    """
    
      # val looks like b'...'
    return f'<a href="data:application/octet-stream;{mid}" download="example.mid">Download midi file with save as</a>' 




with open("105027.mid", 'rb') as inmidi:
    st.markdown(get_midi_download_link(inmidi), unsafe_allow_html=True)