【问题标题】:Boto3 read a file content from S3 key line by lineBoto3 从 S3 密钥中逐行读取文件内容
【发布时间】:2018-05-13 12:06:47
【问题描述】:

使用 boto3,您可以根据给定存储桶名称和密钥,从 S3 中的某个位置读取文件内容(假设初步 import boto3

s3 = boto3.resource('s3')

content = s3.Object(BUCKET_NAME, S3_KEY).get()['Body'].read()

这将返回一个字符串类型。我需要获取的特定文件恰好是一组类似字典的对象,每行一个。所以它不是 JSON 格式。我不想将其作为字符串读取,而是将其作为文件对象流式传输并逐行读取;除了首先在本地下载文件之外找不到其他方法

s3 = boto3.resource('s3')

bucket = s3.Bucket(BUCKET_NAME)

filename = 'my-file'
bucket.download_file(S3_KEY, filename)

f = open('my-file')

我要问的是,是否可以对文件进行这种类型的控制,而不必先在本地下载它?

【问题讨论】:

标签: python amazon-web-services amazon-s3 boto3


【解决方案1】:

我发现 .splitlines() 对我有用...

txt_file = s3.Object(bucket, file).get()['Body'].read().decode('utf-8').splitlines()

如果没有 .splitlines() ,则返回整个文本块,并且尝试迭代每一行会导致每个字符都被迭代。使用 .splitlines() 逐行迭代是可以实现的。

在我的示例中,我遍历每一行并将其编译成一个字典。

txt_file = s3.Object(bucket, file).get()['Body'].read().decode(
        'utf-8').splitlines()

for line in txt_file:
    arr = line.split()
    print(arr)

【讨论】:

    【解决方案2】:

    你也可以利用StreamingBodyiter_lines方法:

    for line in s3.Object(bucket, file).get()['Body'].iter_lines():
        decoded_line = line.decode('utf-b') # if decoding is needed
    

    与一次读取整行然后拆分它相比,这将消耗更少的内存

    【讨论】:

      【解决方案3】:

      kooshiwoosh 到类似问题的以下comment 提供了一个很好的答案:

      from io import TextIOWrapper
      from gzip import GzipFile
      ...
      
      # get StreamingBody from botocore.response
      response = s3.get_object(Bucket=bucket, Key=key)
      # if gzipped
      gzipped = GzipFile(None, 'rb', fileobj=response['Body'])
      data = TextIOWrapper(gzipped)
      
      for line in data:
          # process line
      

      【讨论】:

        【解决方案4】:

        这将完成工作:

        bytes_to_read = 512
        
        content = s3.Object(BUCKET_NAME, S3_KEY).get()['Body'].read(bytes_to_read)
        

        【讨论】:

        • 这只有在 OP 知道每行有多少字节时才有用。这个问题没有表明情况确实如此。事实上,行长似乎更有可能是未知的
        【解决方案5】:

        这对我有用:

        json_object = s3.get_object(Bucket = bucket, Key = json_file_name)
        json_file_reader = json_object['Body'].read()
        content = json.loads(json_file_reader)
        

        【讨论】:

          【解决方案6】:

          到目前为止,您可以使用 download_fileobj 函数。这是一个 CSV 文件的示例:

          import boto3
          import csv
          
          bucket           = 'my_bucket' 
          file_key         = 'my_key/file.csv'
          output_file_path = 'output.csv'
          
          s3 = boto3.resource('s3')
          bucket = s3.Bucket(bucket)
          
          #Dump binary in append mode
          with open(output_file_path, 'ab') as file_object:
              bucket.download_fileobj(
                  Key     = file_key, 
                  Fileobj = file_object,
              )
          
          #Read your file as usual
          with open(output_file_path, 'r') as csvfile:
              lines = csv.reader(csvfile)
              for line in lines:
                  doWhatEver(line[0])
          

          【讨论】:

            猜你喜欢
            • 2016-07-12
            • 2019-05-02
            • 2015-04-21
            • 2019-08-21
            • 2017-04-21
            • 2019-03-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多