source

S3 버킷에서 모든 파일을 다운로드하는 Boto3

nicesource 2023. 7. 23. 14:23
반응형

S3 버킷에서 모든 파일을 다운로드하는 Boto3

나는 s3 버킷에서 파일을 가져오기 위해 boto3를 사용하고 있습니다.▁like니▁a와 비슷한 기능이 합니다.aws s3 sync

나의 현재 코드는

#!/usr/bin/python
import boto3
s3=boto3.client('s3')
list=s3.list_objects(Bucket='my_bucket_name')['Contents']
for key in list:
    s3.download_file('my_bucket_name', key['Key'], key['Key'])

버킷에 파일만 있으면 정상적으로 작동합니다.버킷 안에 폴더가 있으면 해당 폴더가 오류를 발생시킵니다.

Traceback (most recent call last):
  File "./test", line 6, in <module>
    s3.download_file('my_bucket_name', key['Key'], key['Key'])
  File "/usr/local/lib/python2.7/dist-packages/boto3/s3/inject.py", line 58, in download_file
    extra_args=ExtraArgs, callback=Callback)
  File "/usr/local/lib/python2.7/dist-packages/boto3/s3/transfer.py", line 651, in download_file
    extra_args, callback)
  File "/usr/local/lib/python2.7/dist-packages/boto3/s3/transfer.py", line 666, in _download_file
    self._get_object(bucket, key, filename, extra_args, callback)
  File "/usr/local/lib/python2.7/dist-packages/boto3/s3/transfer.py", line 690, in _get_object
    extra_args, callback)
  File "/usr/local/lib/python2.7/dist-packages/boto3/s3/transfer.py", line 707, in _do_get_object
    with self._osutil.open(filename, 'wb') as f:
  File "/usr/local/lib/python2.7/dist-packages/boto3/s3/transfer.py", line 323, in open
    return open(filename, mode)
IOError: [Errno 2] No such file or directory: 'my_folder/.8Df54234'

이것이 boto3를 사용하여 완전한 s3 버킷을 다운로드하는 올바른 방법입니까?폴더를 다운로드하는 방법.

저도 같은 요구를 가지고 있으며 파일을 재귀적으로 다운로드하는 다음과 같은 기능을 만들었습니다.

디렉토리는 파일이 포함된 경우에만 로컬로 작성됩니다.

import boto3
import os

def download_dir(client, resource, dist, local='/tmp', bucket='your_bucket'):
    paginator = client.get_paginator('list_objects')
    for result in paginator.paginate(Bucket=bucket, Delimiter='/', Prefix=dist):
        if result.get('CommonPrefixes') is not None:
            for subdir in result.get('CommonPrefixes'):
                download_dir(client, resource, subdir.get('Prefix'), local, bucket)
        for file in result.get('Contents', []):
            dest_pathname = os.path.join(local, file.get('Key'))
            if not os.path.exists(os.path.dirname(dest_pathname)):
                os.makedirs(os.path.dirname(dest_pathname))
            if not file.get('Key').endswith('/'):
                resource.meta.client.download_file(bucket, file.get('Key'), dest_pathname)

함수를 다음과 같이 부릅니다.

def _start():
    client = boto3.client('s3')
    resource = boto3.resource('s3')
    download_dir(client, resource, 'clientconf/', '/tmp', bucket='my-bucket')

1000개는 1000개 이상의 객체를 .NextContinuationToken최대 1000개 키의 순차적인 세트에서.이 솔루션은 먼저 개체 목록을 컴파일한 다음 지정된 디렉토리를 반복적으로 생성하고 기존 개체를 다운로드합니다.

import boto3
import os

s3_client = boto3.client('s3')

def download_dir(prefix, local, bucket, client=s3_client):
    """
    params:
    - prefix: pattern to match in s3
    - local: local path to folder in which to place files
    - bucket: s3 bucket with target contents
    - client: initialized s3 client object
    """
    keys = []
    dirs = []
    next_token = ''
    base_kwargs = {
        'Bucket':bucket,
        'Prefix':prefix,
    }
    while next_token is not None:
        kwargs = base_kwargs.copy()
        if next_token != '':
            kwargs.update({'ContinuationToken': next_token})
        results = client.list_objects_v2(**kwargs)
        contents = results.get('Contents')
        for i in contents:
            k = i.get('Key')
            if k[-1] != '/':
                keys.append(k)
            else:
                dirs.append(k)
        next_token = results.get('NextContinuationToken')
    for d in dirs:
        dest_pathname = os.path.join(local, d)
        if not os.path.exists(os.path.dirname(dest_pathname)):
            os.makedirs(os.path.dirname(dest_pathname))
    for k in keys:
        dest_pathname = os.path.join(local, k)
        if not os.path.exists(os.path.dirname(dest_pathname)):
            os.makedirs(os.path.dirname(dest_pathname))
        client.download_file(bucket, k, dest_pathname)
import os
import boto3

#initiate s3 resource
s3 = boto3.resource('s3')

# select bucket
my_bucket = s3.Bucket('my_bucket_name')

# download file into current directory
for s3_object in my_bucket.objects.all():
    # Need to split s3_object.key into path and file name, else it will give error file not found.
    path, filename = os.path.split(s3_object.key)
    my_bucket.download_file(s3_object.key, filename)

Amazon S3에는 폴더/디렉토리가 없습니다.플랫 파일 구조입니다.

디렉토리의 모양을 유지하기 위해 경로 이름은 개체 키(파일 이름)의 일부로 저장됩니다.예:

  • images/foo.jpg

는 이경전체입니다.images/foo.jpg뿐만 아니라foo.jpg.

나는 당신의 문제는boto는 다파일반환다라는 하고 있습니다.my_folder/.8Df54234로컬 파일 시스템에 저장하려고 합니다.그나로파시다해음석다니합을이스일템을 해석합니다.my_folder/디렉터리 이름으로 사용할 수 있으며 해당 디렉터리는 로컬 파일 시스템에 없습니다.

파일 이름을 잘라 저장할 수도 있습니다..8Df54234파일을 쓰기 전에 필요한 디렉터리를 만들어야 합니다.다중 수준 중첩 디렉토리일 수 있습니다.

더 쉬운 방법은 다음과 같은 모든 작업을 수행하는 AWS CLI(명령줄 인터페이스)를 사용하는 것입니다.

aws s3 cp --recursive s3://my_bucket_name local_folder

sync새 파일과 수정된 파일만 복사하는 옵션입니다.

저는 현재 다음을 사용하여 과제를 달성하고 있습니다.

#!/usr/bin/python
import boto3
s3=boto3.client('s3')
list=s3.list_objects(Bucket='bucket')['Contents']
for s3_key in list:
    s3_object = s3_key['Key']
    if not s3_object.endswith("/"):
        s3.download_file('bucket', s3_object, s3_object)
    else:
        import os
        if not os.path.exists(s3_object):
            os.makedirs(s3_object)

효과는 있지만, 이런 식으로 하는 것이 좋을지는 잘 모르겠습니다.다른 사용자와 추가 답변을 돕기 위해 더 나은 방법으로 이 문서를 남깁니다.

늦는 것이 안 하는 것보다 낫습니다:)paginator와의 이전 답변은 정말 좋습니다.그러나 재귀적이므로 Python의 재귀 한계에 도달할 수 있습니다.몇 가지 추가적인 점검을 포함한 대안이 있습니다.

import os
import errno
import boto3


def assert_dir_exists(path):
    """
    Checks if directory tree in path exists. If not it created them.
    :param path: the path to check if it exists
    """
    try:
        os.makedirs(path)
    except OSError as e:
        if e.errno != errno.EEXIST:
            raise


def download_dir(client, bucket, path, target):
    """
    Downloads recursively the given S3 path to the target directory.
    :param client: S3 client to use.
    :param bucket: the name of the bucket to download from
    :param path: The S3 directory to download.
    :param target: the local directory to download the files to.
    """

    # Handle missing / at end of prefix
    if not path.endswith('/'):
        path += '/'

    paginator = client.get_paginator('list_objects_v2')
    for result in paginator.paginate(Bucket=bucket, Prefix=path):
        # Download each file individually
        for key in result['Contents']:
            # Calculate relative path
            rel_path = key['Key'][len(path):]
            # Skip paths ending in /
            if not key['Key'].endswith('/'):
                local_file_path = os.path.join(target, rel_path)
                # Make sure directories exist
                local_file_dir = os.path.dirname(local_file_path)
                assert_dir_exists(local_file_dir)
                client.download_file(bucket, key['Key'], local_file_path)


client = boto3.client('s3')

download_dir(client, 'bucket-name', 'path/to/data', 'downloads')

여기에 있는 많은 해결책들은 상당히 복잡해집니다.더 간단한 것을 찾고 있는 경우 디렉터리 또는 파일을 다운로드하는 이 사용 사례에 적합한 방식으로 파일을 포장합니다.

from cloudpathlib import CloudPath

cp = CloudPath("s3://bucket/product/myproject/2021-02-15/")
cp.download_to("local_folder")

의 경우, 참고: 파이많: 더의폴큰경우은,awscli명령행에서는 더 빠를 수 있습니다.

AWS CLI를 동일한 프로세스에서 실행하는 이 문제에 대한 해결 방법이 있습니다.

를 설치합니다.awsclias python lib:

pip install awscli

그런 다음 이 함수를 정의합니다.

from awscli.clidriver import create_clidriver

def aws_cli(*cmd):
    old_env = dict(os.environ)
    try:

        # Environment
        env = os.environ.copy()
        env['LC_CTYPE'] = u'en_US.UTF'
        os.environ.update(env)

        # Run awscli in the same process
        exit_code = create_clidriver().main(*cmd)

        # Deal with problems
        if exit_code > 0:
            raise RuntimeError('AWS CLI exited with code {}'.format(exit_code))
    finally:
        os.environ.clear()
        os.environ.update(old_env)

실행 방법:

aws_cli('s3', 'sync', '/path/to/source', 's3://bucket/destination', '--delete')

그랜트의 답변을 병렬로 실행하도록 업데이트했습니다. 관심 있는 사람이 있다면 훨씬 더 빠릅니다.

from concurrent import futures
import os
import boto3

def download_dir(prefix, local, bucket):

    client = boto3.client('s3')

    def create_folder_and_download_file(k):
        dest_pathname = os.path.join(local, k)
        if not os.path.exists(os.path.dirname(dest_pathname)):
            os.makedirs(os.path.dirname(dest_pathname))
        print(f'downloading {k} to {dest_pathname}')
        client.download_file(bucket, k, dest_pathname)

    keys = []
    dirs = []
    next_token = ''
    base_kwargs = {
        'Bucket': bucket,
        'Prefix': prefix,
    }
    while next_token is not None:
        kwargs = base_kwargs.copy()
        if next_token != '':
            kwargs.update({'ContinuationToken': next_token})
        results = client.list_objects_v2(**kwargs)
        contents = results.get('Contents')
        for i in contents:
            k = i.get('Key')
            if k[-1] != '/':
                keys.append(k)
            else:
                dirs.append(k)
        next_token = results.get('NextContinuationToken')
    for d in dirs:
        dest_pathname = os.path.join(local, d)
        if not os.path.exists(os.path.dirname(dest_pathname)):
            os.makedirs(os.path.dirname(dest_pathname))
    with futures.ThreadPoolExecutor() as executor:
        futures.wait(
            [executor.submit(create_folder_and_download_file, k) for k in keys],
            return_when=futures.FIRST_EXCEPTION,
        )

asyncio/aioboto를 사용하는 또 다른 병렬 다운로더

import os, time
import asyncio
from itertools import chain
import json
from typing import List
from json.decoder import WHITESPACE
import logging
from functools import partial
from pprint import pprint as pp

# Third Party
import asyncpool
import aiobotocore.session
import aiobotocore.config

_NUM_WORKERS = 50


bucket_name= 'test-data'
bucket_prefix= 'etl2/test/20210330/f_api'


async def save_to_file(s3_client, bucket: str, key: str):
    
    response = await s3_client.get_object(Bucket=bucket, Key=key)
    async with response['Body'] as stream:
        content = await stream.read()
    
    if 1:
        fn =f'out/downloaded/{bucket_name}/{key}'

        dn= os.path.dirname(fn)
        if not isdir(dn):
            os.makedirs(dn,exist_ok=True)
        if 1:
            with open(fn, 'wb') as fh:
                fh.write(content)
                print(f'Downloaded to: {fn}')
   
    return [0]


async def go(bucket: str, prefix: str) -> List[dict]:
    """
    Returns list of dicts of object contents

    :param bucket: s3 bucket
    :param prefix: s3 bucket prefix
    :return: list of download statuses
    """
    logging.basicConfig(level=logging.INFO)
    logger = logging.getLogger()

    session = aiobotocore.session.AioSession()
    config = aiobotocore.config.AioConfig(max_pool_connections=_NUM_WORKERS)
    contents = []
    async with session.create_client('s3', config=config) as client:
        worker_co = partial(save_to_file, client, bucket)
        async with asyncpool.AsyncPool(None, _NUM_WORKERS, 's3_work_queue', logger, worker_co,
                                       return_futures=True, raise_on_join=True, log_every_n=10) as work_pool:
            # list s3 objects using paginator
            paginator = client.get_paginator('list_objects')
            async for result in paginator.paginate(Bucket=bucket, Prefix=prefix):
                for c in result.get('Contents', []):
                    contents.append(await work_pool.push(c['Key'], client))

    # retrieve results from futures
    contents = [c.result() for c in contents]
    return list(chain.from_iterable(contents))


def S3_download_bucket_files():
    s = time.perf_counter()
    _loop = asyncio.get_event_loop()
    _result = _loop.run_until_complete(go(bucket_name, bucket_prefix))
    assert sum(_result)==0, _result
    print(_result)
    elapsed = time.perf_counter() - s
    print(f"{__file__} executed in {elapsed:0.2f} seconds.")

먼저 S3에서 파일 목록을 가져온 다음 네트워크에서 데이터를 병렬로 읽는 _NUM_WORKS=50의 ioboto를 사용하여 다운로드합니다.

python을 사용하여 bash 스크립트를 호출하려면 S3 버킷의 폴더에서 로컬 폴더(Linux 시스템)로 파일을 로드하는 간단한 방법이 있습니다.

import boto3
import subprocess
import os

###TOEDIT###
my_bucket_name = "your_my_bucket_name"
bucket_folder_name = "your_bucket_folder_name"
local_folder_path = "your_local_folder_path"
###TOEDIT###

# 1.Load thes list of files existing in the bucket folder
FILES_NAMES = []
s3 = boto3.resource('s3')
my_bucket = s3.Bucket('{}'.format(my_bucket_name))
for object_summary in my_bucket.objects.filter(Prefix="{}/".format(bucket_folder_name)):
#     print(object_summary.key)
    FILES_NAMES.append(object_summary.key)

# 2.List only new files that do not exist in local folder (to not copy everything!)
new_filenames = list(set(FILES_NAMES )-set(os.listdir(local_folder_path)))

# 3.Time to load files in your destination folder 
for new_filename in new_filenames:
    upload_S3files_CMD = """aws s3 cp s3://{}/{}/{} {}""".format(my_bucket_name,bucket_folder_name,new_filename ,local_folder_path)

    subprocess_call = subprocess.call([upload_S3files_CMD], shell=True)
    if subprocess_call != 0:
        print("ALERT: loading files not working correctly, please re-check new loaded files")

AWS S3 Docs(S3 버킷에서 폴더를 사용하는 방법):

Amazon S3에서는 버킷과 개체가 기본 리소스이며 개체가 버킷에 저장됩니다.Amazon S3는 파일 시스템에서 볼 수 있는 계층 구조 대신 평평한 구조를 가지고 있습니다.그러나 조직의 단순성을 위해 Amazon S3 콘솔은 개체를 그룹화하는 수단으로 폴더 개념을 지원합니다.Amazon S3는 개체에 대해 공유 이름 접두사를 사용하여 이 작업을 수행합니다(즉, 개체의 이름은 공통 문자열로 시작합니다).개체 이름은 키 이름이라고도 합니다.

예를 들어 콘솔에 사진이라는 폴더를 생성하고 myphoto.jpg라는 개체를 저장할 수 있습니다.그러면 개체가 키 이름 poto/myphoto.jpg와 함께 저장됩니다. 여기서 poto/는 접두사입니다.

버킷의 에뮬레이트된 디렉토리 구조와 관련하여 "mybucket"에서 현재 디렉토리로 모든 파일을 다운로드하려면(폴더가 로컬로 존재하지 않는 경우 버킷에서 폴더 만들기):

import boto3
import os

bucket_name = "mybucket"
s3 = boto3.client("s3")
objects = s3.list_objects(Bucket = bucket_name)["Contents"]
for s3_object in objects:
    s3_key = s3_object["Key"]
    path, filename = os.path.split(s3_key)
    if len(path) != 0 and not os.path.exists(path):
        os.makedirs(path)
    if not s3_key.endswith("/"):
        download_to = path + '/' + filename if path else filename
        s3.download_file(bucket_name, s3_key, download_to)

모든 파일을 한 번에 가져오는 것은 매우 좋지 않습니다. 일괄적으로 받는 것이 좋습니다.

S3에서 특정 폴더(디렉토리)를 가져오기 위해 사용하는 한 가지 구현은 다음과 같습니다.

def get_directory(directory_path, download_path, exclude_file_names):
    # prepare session
    session = Session(aws_access_key_id, aws_secret_access_key, region_name)
    
    # get instances for resource and bucket
    resource = session.resource('s3')
    bucket = resource.Bucket(bucket_name)

    for s3_key in self.client.list_objects(Bucket=self.bucket_name, Prefix=directory_path)['Contents']:
        s3_object = s3_key['Key']
        if s3_object not in exclude_file_names:
            bucket.download_file(file_path, download_path + str(s3_object.split('/')[-1])

그리고 만약 당신이 아래에 언급된 @John Rohtenstein처럼 CLI를 통해 버킷 전체를 사용하기를 원한다면,

aws s3 cp --recursive s3://bucket_name download_path
for objs in my_bucket.objects.all():
    print(objs.key)
    path='/tmp/'+os.sep.join(objs.key.split(os.sep)[:-1])
    try:
        if not os.path.exists(path):
            os.makedirs(path)
        my_bucket.download_file(objs.key, '/tmp/'+objs.key)
    except FileExistsError as fe:                          
        print(objs.key+' exists')

이 코드는 콘텐츠를 다운로드합니다./tmp/디렉토리입니다.원하는 경우 디렉토리를 변경할 수 있습니다.

저는 비슷한 요구사항을 얻었고 위의 몇 가지 해결책과 다른 웹사이트에서 도움을 받았습니다. 저는 아래의 스크립트를 생각해냈습니다. 누군가에게 도움이 될 수 있다면 공유하고 싶었습니다.

from boto3.session import Session
import os

def sync_s3_folder(access_key_id,secret_access_key,bucket_name,folder,destination_path):    
    session = Session(aws_access_key_id=access_key_id,aws_secret_access_key=secret_access_key)
    s3 = session.resource('s3')
    your_bucket = s3.Bucket(bucket_name)
    for s3_file in your_bucket.objects.all():
        if folder in s3_file.key:
            file=os.path.join(destination_path,s3_file.key.replace('/','\\'))
            if not os.path.exists(os.path.dirname(file)):
                os.makedirs(os.path.dirname(file))
            your_bucket.download_file(s3_file.key,file)
sync_s3_folder(access_key_id,secret_access_key,bucket_name,folder,destination_path)

oserror 20을 피하기 위해 마지막에 if 조건으로 @glefait의 답변을 다시 게시합니다.첫 번째 키는 대상 경로에 쓸 수 없는 폴더 이름 자체입니다.

def download_dir(client, resource, dist, local='/tmp', bucket='your_bucket'):
    paginator = client.get_paginator('list_objects')
    for result in paginator.paginate(Bucket=bucket, Delimiter='/', Prefix=dist):
        if result.get('CommonPrefixes') is not None:
            for subdir in result.get('CommonPrefixes'):
                download_dir(client, resource, subdir.get('Prefix'), local, bucket)
        for file in result.get('Contents', []):
            print("Content: ",result)
            dest_pathname = os.path.join(local, file.get('Key'))
            print("Dest path: ",dest_pathname)
            if not os.path.exists(os.path.dirname(dest_pathname)):
                print("here last if")
                os.makedirs(os.path.dirname(dest_pathname))
            print("else file key: ", file.get('Key'))
            if not file.get('Key') == dist:
                print("Key not equal? ",file.get('Key'))
                resource.meta.client.download_file(bucket, file.get('Key'), dest_pathname)enter code here

저는 한동안 이 문제에 부딪혔고, 제가 겪은 여러 포럼에서 어떤 것이 제대로 작동하는지에 대한 전체적인 정보를 보지 못했습니다.그래서 저는 모든 부분을 가져갔고(스스로 추가) 완전한 엔드 투 엔드 S3 Downloader를 만들었습니다.

이렇게 하면 파일이 자동으로 다운로드될 뿐만 아니라 S3 파일이 하위 디렉터리에 있으면 로컬 저장소에 파일이 생성됩니다.애플리케이션의 경우 권한과 소유자를 설정해야 하므로 이를 추가했습니다(필요하지 않은 경우 주석을 달 수 있음).

이는 Docker 환경(K8)에서 테스트되어 작동하지만 로컬에서 테스트/실행할 경우를 대비하여 스크립트에 환경 변수를 추가했습니다.

이것이 S3 다운로드 자동화를 찾는 데 도움이 되기를 바랍니다.또한 필요한 경우 이를 보다 효율적으로 최적화할 수 있는 방법에 대한 조언, 정보 등을 환영합니다.

#!/usr/bin/python3
import gc
import logging
import os
import signal
import sys
import time
from datetime import datetime

import boto
from boto.exception import S3ResponseError
from pythonjsonlogger import jsonlogger

formatter = jsonlogger.JsonFormatter('%(message)%(levelname)%(name)%(asctime)%(filename)%(lineno)%(funcName)')

json_handler_out = logging.StreamHandler()
json_handler_out.setFormatter(formatter)

#Manual Testing Variables If Needed
#os.environ["DOWNLOAD_LOCATION_PATH"] = "some_path"
#os.environ["BUCKET_NAME"] = "some_bucket"
#os.environ["AWS_ACCESS_KEY"] = "some_access_key"
#os.environ["AWS_SECRET_KEY"] = "some_secret"
#os.environ["LOG_LEVEL_SELECTOR"] = "DEBUG, INFO, or ERROR"

#Setting Log Level Test
logger = logging.getLogger('json')
logger.addHandler(json_handler_out)
logger_levels = {
    'ERROR' : logging.ERROR,
    'INFO' : logging.INFO,
    'DEBUG' : logging.DEBUG
}
logger_level_selector = os.environ["LOG_LEVEL_SELECTOR"]
logger.setLevel(logger_level_selector)

#Getting Date/Time
now = datetime.now()
logger.info("Current date and time : ")
logger.info(now.strftime("%Y-%m-%d %H:%M:%S"))

#Establishing S3 Variables and Download Location
download_location_path = os.environ["DOWNLOAD_LOCATION_PATH"]
bucket_name = os.environ["BUCKET_NAME"]
aws_access_key_id = os.environ["AWS_ACCESS_KEY"]
aws_access_secret_key = os.environ["AWS_SECRET_KEY"]
logger.debug("Bucket: %s" % bucket_name)
logger.debug("Key: %s" % aws_access_key_id)
logger.debug("Secret: %s" % aws_access_secret_key)
logger.debug("Download location path: %s" % download_location_path)

#Creating Download Directory
if not os.path.exists(download_location_path):
    logger.info("Making download directory")
    os.makedirs(download_location_path)

#Signal Hooks are fun
class GracefulKiller:
    kill_now = False
    def __init__(self):
        signal.signal(signal.SIGINT, self.exit_gracefully)
        signal.signal(signal.SIGTERM, self.exit_gracefully)
    def exit_gracefully(self, signum, frame):
        self.kill_now = True

#Downloading from S3 Bucket
def download_s3_bucket():
    conn = boto.connect_s3(aws_access_key_id, aws_access_secret_key)
    logger.debug("Connection established: ")
    bucket = conn.get_bucket(bucket_name)
    logger.debug("Bucket: %s" % str(bucket))
    bucket_list = bucket.list()
#    logger.info("Number of items to download: {0}".format(len(bucket_list)))

    for s3_item in bucket_list:
        key_string = str(s3_item.key)
        logger.debug("S3 Bucket Item to download: %s" % key_string)
        s3_path = download_location_path + "/" + key_string
        logger.debug("Downloading to: %s" % s3_path)
        local_dir = os.path.dirname(s3_path)

        if not os.path.exists(local_dir):
            logger.info("Local directory doesn't exist, creating it... %s" % local_dir)
            os.makedirs(local_dir)
            logger.info("Updating local directory permissions to %s" % local_dir)
#Comment or Uncomment Permissions based on Local Usage
            os.chmod(local_dir, 0o775)
            os.chown(local_dir, 60001, 60001)
        logger.debug("Local directory for download: %s" % local_dir)
        try:
            logger.info("Downloading File: %s" % key_string)
            s3_item.get_contents_to_filename(s3_path)
            logger.info("Successfully downloaded File: %s" % s3_path)
            #Updating Permissions
            logger.info("Updating Permissions for %s" % str(s3_path))
#Comment or Uncomment Permissions based on Local Usage
            os.chmod(s3_path, 0o664)
            os.chown(s3_path, 60001, 60001)
        except (OSError, S3ResponseError) as e:
            logger.error("Fatal error in s3_item.get_contents_to_filename", exc_info=True)
            # logger.error("Exception in file download from S3: {}".format(e))
            continue
        logger.info("Deleting %s from S3 Bucket" % str(s3_item.key))
        s3_item.delete()

def main():
    killer = GracefulKiller()
    while not killer.kill_now:
        logger.info("Checking for new files on S3 to download...")
        download_s3_bucket()
        logger.info("Done checking for new files, will check in 120s...")
        gc.collect()
        sys.stdout.flush()
        time.sleep(120)
if __name__ == '__main__':
    main()

S3가 파일을 구성하는 방식과 Windows가 구성하는 방식에는 매우 사소한 차이가 있습니다.다음은 이러한 차이를 설명하는 간단한 자체 문서화 예제입니다.

또한: 아마존 파일 이름을 일반 문자열로 생각합니다.폴더를 나타내는 것이 아닙니다.Amazon은 폴더를 시뮬레이션하기 때문에 시스템에 없는 폴더 이름에 파일을 밀어넣으려고만 하면 파일을 저장할 위치를 파악할 수 없습니다.따라서 S3의 각 시뮬레이션 폴더에 대해 시스템에 폴더를 만들어야 합니다.폴더 내에 폴더가 있는 경우 "mkdir(경로)"를 사용하지 마십시오."makedirs(경로)"를 사용해야 합니다.또 다른 것! -> PC 파일 경로의 형식이 이상합니다.Amazon은 "/"를 사용하고 pc는 "\"를 사용하며 전체 파일 이름은 동일해야 합니다.아래의 코드 블록을 확인하십시오(인증도 표시됨).

이 예에서는 버킷에 "iTovenGUImages/gui_media"라는 폴더가 있습니다.아직 존재하지 않을 수 있는 내 시스템의 폴더에 넣고 싶습니다.시스템의 폴더에는 폴더 경로처럼 형식이 지정되어 있으면 시스템에서 원하는 대로 지정할 수 있는 고유한 접두사가 있습니다.

import boto3
import cred
import os

locale_file_Imagedirectory = r"C:\\Temp\\App Data\\iToven AI\\"  # This is where all GUI files for iToven AI exist on PC


def downloadImageDirectoryS3(remoteDirectoryName, desired_parent_folder):
    my_bucket = 'itovenbucket'
    s3_resource = boto3.resource('s3', aws_access_key_id=cred.AWSAccessKeyId,
                                 aws_secret_access_key=cred.AWSSecretKey)
    bucket = s3_resource.Bucket(my_bucket)
    for obj in bucket.objects.filter(Prefix=remoteDirectoryName):
        pcVersionPrefix = remoteDirectoryName.replace("/", r"\\")
        isolatedFileName = obj.key.replace(remoteDirectoryName, "")
        clientSideFileName = desired_parent_folder+pcVersionPrefix+isolatedFileName
        print(clientSideFileName)  # Client-Side System File Structure
        if not os.path.exists(desired_parent_folder+pcVersionPrefix):  # CREATE DIRECTORIES FOR EACH FOLDER RECURSIVELY
            os.makedirs(desired_parent_folder+pcVersionPrefix)
        if obj.key not in desired_parent_folder+pcVersionPrefix:
            bucket.download_file(obj.key, clientSideFileName)  # save to new path


downloadImageDirectoryS3(r"iTovenGUIImagesPC/gui_media/", locale_file_Imagedirectory)

언급URL : https://stackoverflow.com/questions/31918960/boto3-to-download-all-files-from-a-s3-bucket

반응형