如何在Lambda/Glue中无需本地暂存将S3文件通过storbinary上传到FTP服务器
解决方案
原有代码的核心错误为
with open(data,"rb") as f行:open()方法第一个参数需要传入本地文件路径,但你传入的是从S3对象读取的二进制字节内容,该行会直接抛出类型错误,导致流程终止。
方案1:使用BytesIO内存处理(适合小于500MB的小文件)
该方案不需要写入本地磁盘,直接在内存中处理,执行效率更高:
import ftplib import boto3 from io import BytesIO # FTP连接配置 FTP_HOST = 'xxx' FTP_PORT = yyy FTP_USER = 'uname' FTP_PASS = 'passwd' FTP_TARGET_DIR = 'path' # S3配置 S3_BUCKET = 'my_bucket' S3_KEY = 'myfolder/myfile.txt' TARGET_FILENAME = 'test12.txt' try: # 初始化FTP连接 ftp = ftplib.FTP() ftp.connect(FTP_HOST, FTP_PORT, timeout=30) ftp.login(FTP_USER, FTP_PASS) ftp.cwd(FTP_TARGET_DIR) # 开启被动模式,大部分公网FTP需要该配置 ftp.set_pasv(True) # 读取S3文件 s3 = boto3.client('s3') s3_resp = s3.get_object(Bucket=S3_BUCKET, Key=S3_KEY) # 直接将二进制内容写入BytesIO对象 file_obj = BytesIO(s3_resp['Body'].read()) # 指针移动到文件开头,否则storbinary会从末尾读取,上传空文件 file_obj.seek(0) # 上传到FTP ftp.storbinary(f'STOR {TARGET_FILENAME}', file_obj) finally: # 确保资源释放 if 'file_obj' in locals(): file_obj.close() if 'ftp' in locals() and ftp.sock: ftp.quit()
如果文件大小超过Glue Python Shell分配的内存,会触发OOM报错,此时请使用方案2。
方案2:使用临时磁盘文件(适合大文件)
利用Glue/Lambda环境的/tmp临时目录存储文件,避免内存溢出:
import ftplib import boto3 import tempfile import os # FTP、S3配置项同上,此处省略 try: # 初始化FTP连接部分同上,此处省略 ftp = ftplib.FTP() ftp.connect(FTP_HOST, FTP_PORT, timeout=30) ftp.login(FTP_USER, FTP_PASS) ftp.cwd(FTP_TARGET_DIR) ftp.set_pasv(True) s3 = boto3.client('s3') # 创建临时文件,自动管理生命周期 with tempfile.NamedTemporaryFile(delete=False, dir='/tmp') as tmp_f: s3.download_fileobj(S3_BUCKET, S3_KEY, tmp_f) tmp_path = tmp_f.name # 上传临时文件到FTP with open(tmp_path, 'rb') as f: ftp.storbinary(f'STOR {TARGET_FILENAME}', f) finally: # 清理临时文件 if 'tmp_path' in locals() and os.path.exists(tmp_path): os.unlink(tmp_path) if 'ftp' in locals() and ftp.sock: ftp.quit()
其他注意事项
- 确保你的Glue执行角色已经配置了目标S3桶的
s3:GetObject权限 - 确保Glue的网络配置可以访问FTP服务器:如果FTP部署在公网,需要为Glue配置公网访问能力;如果FTP部署在私有VPC内,需要为Glue任务配置对应的VPC、子网、安全组,安全组需放行FTP服务的21端口以及被动模式端口段
- 若FTP服务支持FTPS,建议替换
ftplib.FTP为ftplib.FTP_TLS提升传输安全性
内容的提问来源于stack exchange,提问作者Ludwig
相关产品推荐
相关产品推荐

