The file is being uploaded into the app, not being saved on the server per se. It exists as a StringIO or BytesIO object, which you can then use to physically create and save a file. See API docs.
app.py
import os
import time
from random import randint
import streamlit as st
from data import csv_to_df, excel_to_df
# Important: This folder must exist!
SAVE_PATH = os.path.join(os.getcwd(), 'uploads')
state = st.session_state
if 'FILE_UPLOADER_KEY' not in state:
state.FILE_UPLOADER_KEY = str(randint(1000,9999))
st.markdown('## \U0001F4C2 Upload data files')
st.write('Upload one or more Excel data files. Duplicate files will be ignored.')
excel_files = st.file_uploader('', type=['xlsx', 'csv'], accept_multiple_files=True, key=state.FILE_UPLOADER_KEY)
save = st.checkbox(f'Save files in {SAVE_PATH}?')
if len(excel_files) > 0 and st.button('\U00002716 Clear all'):
state.FILE_UPLOADER_KEY = str(randint(1000,9999))
st.experimental_rerun()
# This will remove duplicate files
excel_files_dict = {}
for excel_file in excel_files:
excel_files_dict[excel_file.name] = excel_file
message = st.empty()
for _, excel_file in excel_files_dict.items():
message.info(f'Loading {excel_file.name}...')
if excel_file.type in ['application/vnd.ms-excel', 'application/octet-stream']:
df = csv_to_df(excel_file)
if save:
message.info(f'Saving: {os.path.join(SAVE_PATH, excel_file.name)}')
df.to_csv(os.path.join(SAVE_PATH, excel_file.name))
else: # 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
df = excel_to_df(excel_file)
if save:
message.info(f'Saving: {os.path.join(SAVE_PATH, excel_file.name)}')
df.to_excel(os.path.join(SAVE_PATH, excel_file.name))
st.subheader(excel_file.name)
st.dataframe(df)
if save:
message.info('Your files have been saved.')
else:
message.info('Upload complete.')
time.sleep(2)
message.write('')
data.py
import streamlit as st
import pandas as pd
@st.experimental_memo(persist='disk')
def csv_to_df(excel_file):
df = pd.read_csv(excel_file)
return df
@st.experimental_memo(persist='disk')
def excel_to_df(excel_file):
# https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_excel.html
# New in Pandas version 1.3.0.
# The engine xlrd now only supports old-style .xls files. When engine=None, the following logic will be used to determine the engine:
# If path_or_buffer is an OpenDocument format (.odf, .ods, .odt), then odf will be used.
# Otherwise if path_or_buffer is an xls format, xlrd will be used.
# Otherwise if path_or_buffer is in xlsb format, pyxlsb will be used.
# Otherwise openpyxl will be used.
#
# import openpyxl
# df = pd.read_excel(excel_file, engine=openpyxl)
#
# Therefore... do not need to provide "engine" when using a "path_or_buffer"
df = pd.read_excel(excel_file)
return df
Screenshot
This solution has been adapted from code I wrote here.