Python读取S3二进制CSV文件乱码问题及解决方案咨询
问题:Lambda读取S3中CSV文件出现乱码,无法正确解析
Lambda函数以wb模式从邮件读取内容并上传CSV到S3,上传代码如下:
open('/tmp/' + filename, 'wb').write(part.get_payload(decode=True)) s3r.meta.client.upload_file('/tmp/' + filename)
读取时使用以下代码,但输出为乱码字节串:
client = boto3.client('s3') data = client.get_object(Bucket=bucket_name, Key= key) with io.TextIOWrapper(data["Body"], encoding='latin1') as text_file: reader = csv.DictReader(text_file, delimiter=',') for row in reader: print(row)
乱码内容示例:
\x1bdº\x9e\x8f\x90dN\x18"m': '\x00\x80\x02\x00\x000\x8f\x18\x00\x00\x00', "à¥Ç\x9eDO97*\x82~§Èɸ8ÀOíc\x1c|n¦Ñ\x07ä\x04Eøÿ\x14ö\x11éºóÀB\x10ÉÀ!$}\x87íàÈé;{ìÐå[\x83îñ\x96é\x7f2þ\x06\x00\x00ÿÿ\x03\x00PK\x03\x04\x14\x00\x06\x00\x08\x00\x00\x00!\x00µU0#ô\x00\x00\x00L\x02\x00\x00\x0b\x00\x08\x02_rels/.rels ¢\x04\x02(\xa0\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00¬\x92MOÃ0\x0c\x86ïHü\x87È÷ÕÝ\x90\x10BKwAH»!T~\x80IÜ\x0fµ\x8d£$\x1bÝ¿'\x1c\x10T\x1a\x83\x03G\x7f½~üÊÛÝ<\x8dê
原因分析
乱码内容中出现PK标识,说明上传的并非纯CSV文件,而是ZIP压缩包。邮件附件可能本身是压缩后的ZIP格式(CSV被打包成ZIP作为附件),但当前代码直接将解码后的附件内容当作CSV写入并上传,导致S3存储的是ZIP文件,读取时按纯文本解析就会出现乱码。
解决步骤
1. 修正上传逻辑:先解压再上传CSV
如果邮件附件是ZIP包,需先解压获取内部的CSV文件,再上传至S3:
import zipfile from io import BytesIO # 读取邮件附件的二进制内容 payload = part.get_payload(decode=True) # 将二进制内容包装为可读取的ZIP文件对象 zip_file = zipfile.ZipFile(BytesIO(payload)) # 获取ZIP内的第一个文件(假设仅包含目标CSV) csv_filename = zip_file.namelist()[0] # 读取CSV文件内容 csv_content = zip_file.read(csv_filename) # 写入临时文件并上传到S3 with open('/tmp/' + csv_filename, 'wb') as f: f.write(csv_content) s3r.meta.client.upload_file('/tmp/' + csv_filename, bucket_name, s3_key)
2. 修正读取逻辑:解压已上传的ZIP文件
如果S3中已经存储了ZIP文件,读取时需先解压再解析CSV:
import zipfile from io import BytesIO import csv import boto3 client = boto3.client('s3') data = client.get_object(Bucket=bucket_name, Key=key) # 获取ZIP文件的二进制内容 zip_content = data["Body"].read() # 解压ZIP文件 zip_file = zipfile.ZipFile(BytesIO(zip_content)) csv_filename = zip_file.namelist()[0] # 读取并解析CSV,同时修改内容 with zip_file.open(csv_filename, 'r') as csv_file: # 根据CSV实际编码调整(如utf-8、gbk等) csv_lines = csv_file.read().decode('utf-8').splitlines() reader = csv.DictReader(csv_lines) for row in reader: # 示例:修改指定列的内容 if 'old_value' in row['target_column']: row['target_column'] = row['target_column'].replace('old_value', 'new_value') print(row)
3. 可选:自动判断附件格式
上传前可先判断附件是否为ZIP,兼容纯CSV和压缩包两种情况:
import zipfile from io import BytesIO payload = part.get_payload(decode=True) # 判断是否为ZIP文件 is_zip = zipfile.is_zipfile(BytesIO(payload)) if is_zip: # 按ZIP解压处理 zip_file = zipfile.ZipFile(BytesIO(payload)) csv_filename = zip_file.namelist()[0] csv_content = zip_file.read(csv_filename) with open('/tmp/' + csv_filename, 'wb') as f: f.write(csv_content) s3r.meta.client.upload_file('/tmp/' + csv_filename, bucket_name, s3_key) else: # 按纯CSV直接上传 with open('/tmp/' + filename, 'wb') as f: f.write(payload) s3r.meta.client.upload_file('/tmp/' + filename, bucket_name, s3_key)
内容的提问来源于stack exchange,提问作者Md. Parvez Alam
相关产品推荐
相关产品推荐

