为什么 boto3.client.download_file 在文件名末尾附加一个字符串?

giu*_*osa 3 python amazon-s3 amazon-web-services python-requests boto3

我需要从 s3 下载文件,并创建以下代码:

#This function make the download of the files in a bucket 
def download_dir(s3:boto3.client, bucket:str, directory:str=None) -> None:
    
    #Verify if exist the bucket diretory
    if not os.path.exists(bucket):
                #Creating the bucket directory
                os.makedirs(bucket)
    
    # Iterating in s3 list of objects inside of the bucket
    for s3_key in s3.list_objects(Bucket=bucket)['Contents']:
        
        file_name=os.path.join(bucket, s3_key['Key'])
        #If the object is not a directory
        if not s3_key['Key'].endswith("/"):
            #Verify if the download file was already done  
            if not os.path.exists(file_name):
                print(s3_key['Key'])
                real_file_name = s3_key['Key']
                print(real_file_name)
                try:
                    s3.download_file(Bucket=bucket,Key=s3_key['Key'], Filename=file_name)
                except:
                    print(type(real_file_name))
                    s3.download_file(Bucket=bucket, Filename=file_name, Key=real_file_name)
        #If the object is a directory
        else:
            #If the directory doesn't exist
            if not os.path.exists(file_name):
                #Creating the directory
                os.makedirs(file_name)
    

s3 = boto3.client('s3',
                verify=False,
                aws_access_key_id=aws_dict['aws_access_key_id'], 
                aws_secret_access_key=aws_dict['aws_secret_access_key'], 
                aws_session_token=aws_dict['aws_session_token'],
                region_name=aws_dict['region_name'],
                config=config
                )

download_dir(s3, 'MY-BUCKET')

Run Code Online (Sandbox Code Playgroud)

但是在特定文件中,神奇的是在存储桶文件名的末尾附加另一个字符串,这给我带来了一个例外:

回溯(最近一次调用最后一次):文件“aws_transfer.py”,第 58 行,在 download_dir(s3, 'bucket') 文件“aws_transfer.py”,第 29 行,在 download_dir s3.download_file(Bucket=bucket, Filename=file_name , Key=real_file_name) 文件 "/home/gbarbo3/.local/lib/python3.8/site-packages/boto3/s3/inject.py", 第 171 行,在 download_file 中 return transfer.download_file( 文件 "/home/gbarbo3 /.local/lib/python3.8/site-packages/boto3/s3/transfer.py”,第 315 行,在 download_file future.result() 文件“/home/gbarbo3/.local/lib/python3.8/site -packages/s3transfer/futures.py”,第106行,结果返回 self._coordinator.result() 文件“/home/gbarbo3/.local/lib/python3.8/site-packages/s3transfer/futures.py”,第265行,结果提高了自我。_exception 文件“/home/gbarbo3/.local/lib/python3.8/site-packages/s3transfer/tasks.py”,第 126 行,位于调用 return self._execute_main(kwargs) 文件“/home/gbarbo3/.local/lib/python3.8/site-packages/s3transfer/tasks.py”,第 150 行,在 _execute_main return_value = self._main(**kwargs)文件“/home/gbarbo3/.local/lib/python3.8/site-packages/s3transfer/download.py”,第 571 行,在 _main fileobj.seek(offset) 文件“/home/gbarbo3/.local/lib/ python3.8/site-packages/s3transfer/utils.py”,第367行,在seek self._open_if_needed()文件“/home/gbarbo3/.local/lib/python3.8/site-packages/s3transfer/utils.py ”,第 350 行,在 _open_if_needed self._fileobj = self._open_function(self._filename, self._mode) 文件“/home/gbarbo3/.local/lib/python3.8/site-packages/s3transfer/utils.py”中,第 261 行,在 open return open(filename, mode) FileNotFoundError: [Errno 2] No such file or directory: 'bucket/folder/model.tar.gz.c40fF924'

真实文件名必须是“bucket/folder/model.tar.gz”。

有人能帮我吗?

Joh*_*ein 6

您的程序在子目录方面存在问题。

首先,解释一下...

Amazon S3 不使用目录。例如,您可以运行以下命令来上传文件:

aws s3 cp foo.txt s3://bucketname/folder1/foo.txt
Run Code Online (Sandbox Code Playgroud)

该对象将在 Amazon S3 存储桶中创建,带有Keyof folder1/foo.txt。如果您在 S3 管理控制台中查看存储桶,该folder1目录会“出现”,但实际上并不存在。如果您要删除该对象,该folder1目录将“消失”,因为它实际上从未存在过。

但是,S3 管理控制台中还有一个名为“创建文件夹”的按钮。它将创建一个名为“文件夹”名称的零长度对象(例如folder1/)。这将“强制”(假装)目录出现,但它实际上仍然不存在。

您的代码专门检查此行中是否存在这样的对象:

if not s3_key['Key'].endswith("/"):
Run Code Online (Sandbox Code Playgroud)

假设总是存在一个具有目录名称的对象。然而,这不一定是真的(如我上面的例子所示)。因此,程序永远不会创建该目录,并且在尝试将对象下载到计算机上不存在的目录时会失败

在下载每个对象之前,您的程序需要测试本地计算机上目标目录是否存在。/它不能依赖于存储桶中的每个目录始终存在一个具有以 结尾的 Key 的对象。