You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Streamlit上传文件至S3报错:filename must be a path 求助

问题:Streamlit上传文件到S3报错"filename must be a path"

我用Streamlit开发的应用要把文件上传到S3存储桶,但遇到错误:filename must be a path。发现Streamlit会临时存储上传的文件,但拿不到临时文件路径,打印也没结果;之前指定本地文件路径上传的代码是正常运行的。

原代码如下:

import streamlit as st
import requests
from dotenv import load_dotenv
import boto3
from botocore.exceptions import NoCredentialsError, PartialCredentialsError,ClientError
import io
import os
import time

def upload_to_s3(file_path,bucket_name,object_name=None):
    
    s3=boto3.client("s3")
    if object_name is None:
        object_name=file_path
    try:
     s3.upload_file(file_path,bucket_name,object_name)
    except ClientError as e:
        print("Client error occured {e}")


def main():
    bucket="shellkode1111"
    st.set_page_config(page_title="apptech",layout="wide")
    st.title("Apple")
    uploaded_file=st.file_uploader("Upload file",type=["mp4"])
    s3=boto3.client("s3")
    sts=boto3.client("sts")
    response = s3.head_bucket(Bucket="shellkode1111")
    try:
        s3.upload_file(uploaded_file,bucket,uploaded_file.name)
    except ClientError as e:
        print("Client Error occured {e}")
    print(response)
    bucket="shellkode1111"
    print("------------------------------")
    print(uploaded_file)
    print("----------------------------------")
    print("Working1")
    if(uploaded_file):
        print("Working")
        response=upload_to_s3(uploaded_file,bucket,uploaded_file)


if __name__== "__main__":
    main()

问题原因

  • Streamlit的st.file_uploader()返回的是UploadedFile对象(类文件对象),并非本地文件路径字符串,而boto3的s3.upload_file()方法要求第一个参数必须是本地文件的路径,直接传入对象会触发路径错误。
  • 原代码中调用upload_to_s3时,第三个参数错误传入了uploaded_file对象,应该传入文件名或自定义的S3对象名。

解决方案

使用boto3的upload_fileobj()方法,该方法支持直接上传类文件对象,无需本地路径。修改后的代码如下:

import streamlit as st
import boto3
from botocore.exceptions import NoCredentialsError, PartialCredentialsError, ClientError
from dotenv import load_dotenv
import os

# 加载环境变量(确保AWS密钥配置正确)
load_dotenv()

def upload_to_s3(file_obj, bucket_name, object_name):
    s3 = boto3.client("s3")
    try:
        # 使用upload_fileobj上传类文件对象
        s3.upload_fileobj(file_obj, bucket_name, object_name)
        return True
    except ClientError as e:
        print(f"客户端错误: {e}")
        return False
    except NoCredentialsError:
        print("未找到AWS凭证,请检查配置")
        return False
    except PartialCredentialsError:
        print("AWS凭证不完整,请检查配置")
        return False

def main():
    bucket = "shellkode1111"
    st.set_page_config(page_title="apptech", layout="wide")
    st.title("Apple")
    
    uploaded_file = st.file_uploader("Upload file", type=["mp4"])
    
    # 验证桶是否存在(可选)
    s3 = boto3.client("s3")
    try:
        s3.head_bucket(Bucket=bucket)
        st.success(f"已连接到存储桶: {bucket}")
    except ClientError as e:
        st.error(f"无法连接到存储桶: {bucket},错误: {e}")
        return
    
    if uploaded_file:
        st.info(f"准备上传文件: {uploaded_file.name}")
        # 重置文件指针到开头(避免读取为空)
        uploaded_file.seek(0)
        # 调用上传函数,传入文件对象和文件名
        if upload_to_s3(uploaded_file, bucket, uploaded_file.name):
            st.success(f"文件 {uploaded_file.name} 上传成功!")
        else:
            st.error("文件上传失败,请检查日志")

if __name__ == "__main__":
    main()

关键修改点

  1. 替换s3.upload_file()为s3.upload_fileobj(),直接接收Streamlit返回的UploadedFile对象
  2. 重构upload_to_s3函数,参数改为文件对象和明确的S3对象名,移除错误的路径逻辑
  3. 添加uploaded_file.seek(0)确保文件指针在开头,避免读取内容为空
  4. 完善异常捕获,区分凭证错误、客户端错误等场景,方便排查问题
  5. 用Streamlit的st.success/st.error替代控制台打印,在页面展示状态反馈

内容的提问来源于stack exchange,提问作者sam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 02:15:11