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

求助:AWS Lambda实现S3间JSON转CSV上传遇只读文件系统错误

问题分析与解决方案

首先,你碰到的[Errno 30] Read-only file system错误是AWS Lambda运行环境的典型限制导致的:Lambda的默认工作目录是只读的,只有/tmp目录是可读写的,你直接尝试创建data.csv会因为没有写入权限而失败。

除此之外,你的代码还有几个小问题需要修正:

  • 变量data未定义,应该用你已经声明的json_data
  • s3对象没有初始化,直接调用s3.Object会报错
  • 两次打开文件可以优化,甚至可以直接在内存中处理CSV,避免磁盘IO

修正后的代码方案

方案1:使用/tmp目录写入临时文件

这是最直接的修改,把文件路径替换为/tmp/data.csv,同时修复其他问题:

import boto3
import botocore
import csv

def lambda_handler(event, context):
    # 初始化S3资源
    s3 = boto3.resource('s3')
    
    BUCKET_NAME = 'name of the bucket' # 替换为你的目标桶名称
    KEY = 'OUTPUT.csv' # 替换为目标对象的key
    json_data = [{"id":"1","name":"test"},{"id":"2","name":"good"}]
    
    # 使用/tmp目录存储临时CSV文件
    csv_file_path = '/tmp/data.csv'
    with open(csv_file_path, "w") as file:
        csv_writer = csv.writer(file)
        csv_writer.writerow(['id', 'name'])
        # 修复变量名错误:data -> json_data
        for item in json_data:
            csv_writer.writerow([item.get('id'), item.get('name')])
    
    # 读取生成的CSV文件并上传到S3
    try:
        obj = s3.Object(BUCKET_NAME, KEY)
        with open(csv_file_path, 'rb') as file:
            obj.put(Body=file.read())
    except botocore.exceptions.ClientError as e:
        if e.response['Error']['Code'] == "404":
            print("目标存储桶不存在或无法访问。")
        else:
            raise
    
    # 生成预签名URL
    s3client = boto3.client('s3')
    try:
        download_url = s3client.generate_presigned_url(
            'get_object',
            Params={
                'Bucket': BUCKET_NAME,
                'Key': KEY
            },
            ExpiresIn=3600
        )
        return {"csv_link": download_url}
    except Exception as e:
        # 若utils_exception是自定义模块,可保留;否则直接抛出错误即可
        raise e

方案2:使用内存流(更高效)

如果你的JSON数据不大,完全可以不用写入磁盘,直接用io.StringIO在内存中生成CSV,这样更快也避免了磁盘操作:

import boto3
import botocore
import csv
from io import StringIO

def lambda_handler(event, context):
    s3 = boto3.resource('s3')
    
    BUCKET_NAME = 'name of the bucket'
    KEY = 'OUTPUT.csv'
    json_data = [{"id":"1","name":"test"},{"id":"2","name":"good"}]
    
    # 使用内存流生成CSV
    csv_buffer = StringIO()
    csv_writer = csv.writer(csv_buffer)
    csv_writer.writerow(['id', 'name'])
    for item in json_data:
        csv_writer.writerow([item.get('id'), item.get('name')])
    
    # 上传内存中的CSV内容到S3(注意转成字节流)
    try:
        obj = s3.Object(BUCKET_NAME, KEY)
        obj.put(Body=csv_buffer.getvalue().encode('utf-8'))
    except botocore.exceptions.ClientError as e:
        if e.response['Error']['Code'] == "404":
            print("目标存储桶不存在或无法访问。")
        else:
            raise
    
    s3client = boto3.client('s3')
    try:
        download_url = s3client.generate_presigned_url(
            'get_object',
            Params={
                'Bucket': BUCKET_NAME,
                'Key': KEY
            },
            ExpiresIn=3600
        )
        return {"csv_link": download_url}
    except Exception as e:
        raise e

关键修改点说明

  • 使用/tmp目录:Lambda的/tmp目录是唯一可读写的临时存储,最大容量为512MB,适合存储临时文件
  • 变量名修正:将未定义的data替换为你实际的数据源json_data
  • 初始化S3资源:在调用s3.Object前必须先通过boto3.resource('s3')创建S3资源对象
  • 内存流优化:避免磁盘IO,提升函数执行效率,尤其适合小数据量的转换

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 10:02:55