boto3-s3存储文件

Posted by Shallow Dreameron June 18, 2024

使用 boto3 库与 AWS S3 进行交互是非常方便和强大的。以下是一些常见的操作,包括多文件上传、列出文件、下载文件和删除文件。

首先,需要安装 boto3

pip install boto3

接下来是一些示例代码:

设置 AWS 凭证和配置

确保在您的环境中设置了 AWS 凭证和配置。可以通过配置文件或环境变量来设置。这里是使用配置文件的方法:

  1. 创建或编辑 ~/.aws/credentials 文件:
    [default]
    aws_access_key_id = YOUR_ACCESS_KEY
    aws_secret_access_key = YOUR_SECRET_KEY
    
  2. 创建或编辑 ~/.aws/config 文件:
    [default]
    region = YOUR_REGION
    

初始化 S3 客户端

import boto3

s3_client = boto3.client('s3')

多文件上传

要上传多个文件,可以使用一个简单的循环来实现:

import os

def upload_files(file_names, bucket_name, s3_client):
    for file_name in file_names:
        s3_client.upload_file(file_name, bucket_name, os.path.basename(file_name))
        print(f'Uploaded {file_name} to {bucket_name}')

# 示例使用
file_names = ['file1.txt', 'file2.txt', 'file3.txt']
bucket_name = 'your-s3-bucket-name'
upload_files(file_names, bucket_name, s3_client)

列出文件

列出 S3 存储桶中的文件:

def list_files(bucket_name, s3_client):
    response = s3_client.list_objects_v2(Bucket=bucket_name)
    if 'Contents' in response:
        for obj in response['Contents']:
            print(obj['Key'])
    else:
        print(f'No files found in {bucket_name}')

# 示例使用
list_files(bucket_name, s3_client)

下载文件

从 S3 下载文件:

def download_file(file_name, bucket_name, s3_client, destination):
    s3_client.download_file(bucket_name, file_name, destination)
    print(f'Downloaded {file_name} to {destination}')

# 示例使用
download_file('file1.txt', bucket_name, s3_client, 'downloaded_file1.txt')

删除文件

从 S3 删除文件:

def delete_file(file_name, bucket_name, s3_client):
    s3_client.delete_object(Bucket=bucket_name, Key=file_name)
    print(f'Deleted {file_name} from {bucket_name}')

# 示例使用
delete_file('file1.txt', bucket_name, s3_client)

删除多个文件

删除 S3 中的多个文件:

def delete_files(file_names, bucket_name, s3_client):
    objects = [{'Key': file_name} for file_name in file_names]
    response = s3_client.delete_objects(Bucket=bucket_name, Delete={'Objects': objects})
    for deleted in response.get('Deleted', []):
        print(f"Deleted {deleted['Key']}")

# 示例使用
delete_files(['file1.txt', 'file2.txt'], bucket_name, s3_client)

通过这些代码示例,你可以方便地进行多文件上传、列出文件、下载文件和删除文件等操作。根据实际需求,你可能需要进行更多的错误处理和异常处理,以确保代码的健壮性和稳定性。


boto3 的配置中,endpoint_url 属性用于指定 AWS 服务的自定义端点。这在以下几种情况下非常有用:

  1. 非 AWS 的 S3 兼容存储服务: 如果你使用的是一个兼容 S3 API 的非 AWS 的存储服务(如 MinIO、DigitalOcean Spaces、Wasabi 等),你需要指定服务的端点 URL。

  2. 区域化端点: AWS S3 在多个区域提供服务,每个区域有不同的端点。如果你需要明确指定某个区域的端点,可以使用这个属性。

  3. 本地开发和测试: 如果你在本地运行一个 S3 的模拟服务进行开发和测试(如 localstack),需要设置 endpoint_url 来指向本地服务。

使用示例

以下是如何在 boto3 中设置 endpoint_url 的示例:

import boto3

# 自定义端点 URL
endpoint_url = 'https://custom-s3-endpoint.com'

s3_client = boto3.client(
    's3',
    endpoint_url=endpoint_url,
    aws_access_key_id='YOUR_ACCESS_KEY',
    aws_secret_access_key='YOUR_SECRET_KEY',
    region_name='YOUR_REGION'
)

# 示例操作
bucket_name = 'your-s3-bucket-name'

# 列出文件
def list_files(bucket_name, s3_client):
    response = s3_client.list_objects_v2(Bucket=bucket_name)
    if 'Contents' in response:
        for obj in response['Contents']:
            print(obj['Key'])
    else:
        print(f'No files found in {bucket_name}')

list_files(bucket_name, s3_client)

配置文件中使用 endpoint_url

在一些情况下,你可能会使用配置文件(如 ~/.aws/config)来设置端点 URL。这可以简化代码中的配置。

~/.aws/config 文件示例:

[default]
region = YOUR_REGION
endpoint_url = https://custom-s3-endpoint.com

使用配置文件:

import boto3

s3_client = boto3.client('s3')

# 示例操作
bucket_name = 'your-s3-bucket-name'

# 列出文件
def list_files(bucket_name, s3_client):
    response = s3_client.list_objects_v2(Bucket=bucket_name)
    if 'Contents' in response:
        for obj in response['Contents']:
            print(obj['Key'])
    else:
        print(f'No files found in {bucket_name}')

list_files(bucket_name, s3_client)

注意事项

  • 确保 endpoint_url 的值正确无误,否则可能会导致连接失败。
  • 使用自定义端点时,需要确保其他配置(如访问密钥、区域等)也正确无误。
  • 在使用本地模拟服务进行开发和测试时,记得在实际部署时移除或修改这些设置,以确保连接到正确的生产环境。

endpoint_url 是一个非常有用的属性,允许你灵活地指定和使用不同的 S3 服务端点,满足各种开发和部署需求。


如果你有一个函数仅支持本地文件系统路径(例如使用标准的文件操作函数如open()),而你希望使用 AWS S3 对象来支持这个函数,你可以通过以下方式进行适配:

使用 BytesIO 进行适配

在 Python 中,可以使用 BytesIO 来模拟文件对象,这样可以在不改变函数接口的情况下,将 S3 对象包装为类似文件的对象。

示例代码

假设你有一个函数 process_file() 需要一个路径来读取文件内容:

import boto3
from io import BytesIO

def process_file(file_path):
    with open(file_path, 'r') as f:
        content = f.read()
        # 处理文件内容的函数逻辑
        return content

def read_s3_object(bucket_name, key):
    s3_client = boto3.client('s3')
    try:
        response = s3_client.get_object(Bucket=bucket_name, Key=key)
        s3_object = response['Body'].read()
        # 将 S3 对象转换为类似文件的对象
        file_like_object = BytesIO(s3_object)
        content = process_file(file_like_object)
        return content
    except Exception as e:
        print(f"Error reading S3 object: {e}")
        return None

解释

  1. process_file() 函数:模拟处理文件内容的函数,它接受一个文件路径,并返回文件内容。

  2. read_s3_object() 函数

    • 使用 boto3 获取 S3 对象。
    • 读取 S3 对象的内容。
    • 使用 BytesIO 将 S3 对象转换为类似文件的对象。
    • 调用 process_file() 函数处理类似文件的对象,获得文件内容。

注意事项

  • 内存消耗:使用 BytesIO 可能会导致整个文件内容加载到内存中,因此适合处理小文件或具有预期大小的文件。
  • 性能考虑:对于大文件或需要频繁读写的情况,建议优化内存使用和性能。

通过这种方式,你可以利用现有的函数处理逻辑,同时兼容处理 AWS S3 对象,从而无需修改原始函数的接口和功能。


使用 boto3 可以轻松地从 Amazon S3 获取文件对象并对其进行读写操作。以下是如何在 Django 应用中使用 boto3 获取 S3 文件对象并对其进行读写操作的示例:

安装 boto3

如果还没有安装 boto3,可以使用以下命令进行安装:

pip install boto3

配置 AWS 凭证

确保在 Django 的 settings.py 文件中配置了 AWS 凭证和 S3 存储桶的相关信息:

AWS_ACCESS_KEY_ID = 'your-aws-access-key-id'
AWS_SECRET_ACCESS_KEY = 'your-aws-secret-access-key'
AWS_STORAGE_BUCKET_NAME = 'your-s3-bucket-name'
AWS_S3_REGION_NAME = 'your-region'  # 示例:us-west-2

读写 S3 文件对象

以下是一个在 Django 视图中使用 boto3 进行读写操作的示例:

读取 S3 文件对象

import boto3
from django.conf import settings
from django.http import JsonResponse

def read_s3_file(request, filename):
    s3_client = boto3.client(
        's3',
        region_name=settings.AWS_S3_REGION_NAME,
        aws_access_key_id=settings.AWS_ACCESS_KEY_ID,
        aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY
    )

    try:
        response = s3_client.get_object(Bucket=settings.AWS_STORAGE_BUCKET_NAME, Key=filename)
        file_content = response['Body'].read().decode('utf-8')
        return JsonResponse({'file_content': file_content})
    except Exception as e:
        return JsonResponse({'error': str(e)}, status=500)

写入 S3 文件对象

import boto3
from django.conf import settings
from django.http import JsonResponse

def write_s3_file(request, filename):
    s3_client = boto3.client(
        's3',
        region_name=settings.AWS_S3_REGION_NAME,
        aws_access_key_id=settings.AWS_ACCESS_KEY_ID,
        aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY
    )

    try:
        # 示例内容,实际内容可以从请求中获取
        file_content = "This is a test content"
        s3_client.put_object(Bucket=settings.AWS_STORAGE_BUCKET_NAME, Key=filename, Body=file_content)
        return JsonResponse({'message': 'File written successfully'})
    except Exception as e:
        return JsonResponse({'error': str(e)}, status=500)

配置 URL 路径

urls.py 中添加路径:

from django.urls import path
from .views import read_s3_file, write_s3_file

urlpatterns = [
    path('read-s3-file/<str:filename>/', read_s3_file, name='read_s3_file'),
    path('write-s3-file/<str:filename>/', write_s3_file, name='write_s3_file'),
]

测试 API

你可以通过浏览器或 API 客户端(如 Postman)访问以下 URL 来测试文件读写操作:

  • 读取文件内容:http://your-domain/read-s3-file/example.txt
  • 写入文件内容:http://your-domain/write-s3-file/example.txt

完整示例

以下是完整的 views.py 示例,包括读取和写入 S3 文件对象的操作:

import boto3
from django.conf import settings
from django.http import JsonResponse

def read_s3_file(request, filename):
    s3_client = boto3.client(
        's3',
        region_name=settings.AWS_S3_REGION_NAME,
        aws_access_key_id=settings.AWS_ACCESS_KEY_ID,
        aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY
    )

    try:
        response = s3_client.get_object(Bucket=settings.AWS_STORAGE_BUCKET_NAME, Key=filename)
        file_content = response['Body'].read().decode('utf-8')
        return JsonResponse({'file_content': file_content})
    except Exception as e:
        return JsonResponse({'error': str(e)}, status=500)

def write_s3_file(request, filename):
    s3_client = boto3.client(
        's3',
        region_name=settings.AWS_S3_REGION_NAME,
        aws_access_key_id=settings.AWS_ACCESS_KEY_ID,
        aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY
    )

    try:
        file_content = "This is a test content"
        s3_client.put_object(Bucket=settings.AWS_STORAGE_BUCKET_NAME, Key=filename, Body=file_content)
        return JsonResponse({'message': 'File written successfully'})
    except Exception as e:
        return JsonResponse({'error': str(e)}, status=500)

通过以上示例,你可以在 Django 应用中使用 boto3 轻松实现对 S3 文件对象的读取和写入操作。


如果文件可能很大,并且你不希望将整个文件加载到内存中,可以使用临时文件系统。Python 的 tempfile 模块提供了创建临时文件的功能,你可以将 S3 对象下载到临时文件,然后将该临时文件的路径传递给需要文件路径的函数。

以下是一个示例,展示如何使用临时文件来处理可能很大的 S3 文件:

示例代码

import boto3
import tempfile
import os

def process_file(file_path):
    with open(file_path, 'r') as f:
        content = f.read()
        # 处理文件内容的函数逻辑
        return content

def read_s3_object(bucket_name, key):
    s3_client = boto3.client('s3')
    try:
        # 创建临时文件
        with tempfile.NamedTemporaryFile(delete=False) as tmp_file:
            # 下载 S3 对象到临时文件
            s3_client.download_fileobj(bucket_name, key, tmp_file)
            temp_file_path = tmp_file.name
        
        # 调用需要文件路径的函数
        content = process_file(temp_file_path)

        # 删除临时文件
        os.remove(temp_file_path)

        return content
    except Exception as e:
        print(f"Error reading S3 object: {e}")
        return None

解释

  1. process_file() 函数:模拟处理文件内容的函数,它接受一个文件路径,并返回文件内容。

  2. read_s3_object() 函数

    • 使用 boto3 获取 S3 对象。
    • 创建一个临时文件,使用 tempfile.NamedTemporaryFile,设置 delete=False 以便手动删除文件。
    • 使用 boto3download_fileobj 方法将 S3 对象下载到临时文件。
    • 将临时文件的路径传递给 process_file() 函数处理文件。
    • 处理完文件后,删除临时文件。

注意事项

  • 临时文件存储位置:默认情况下,tempfile 模块会在系统默认的临时目录中创建文件。你可以通过设置环境变量或在 NamedTemporaryFile 中指定 dir 参数来改变此行为。
  • 文件权限:确保临时文件的权限和安全性。默认情况下,临时文件仅对当前用户可读写。
  • 清理临时文件:确保在处理完文件后删除临时文件,以避免占用磁盘空间。

通过这种方式,你可以有效处理可能很大的 S3 文件,避免将整个文件加载到内存中,同时仍然可以利用需要文件路径的现有函数逻辑。


如果你希望直接将从 S3 读取的内容转换为一个 Python 文件对象,并且包含文件名而不使用临时文件,可以创建一个自定义文件对象类。这个自定义类会包含文件内容和文件名,并实现必要的文件方法,使其行为类似于文件对象。

示例代码

下面是如何实现一个自定义的文件对象类,并使用它来处理从 S3 读取的文件内容:

import boto3
from io import StringIO, BytesIO

class S3FileObject:
    def __init__(self, file_content, file_name):
        self.file_content = file_content
        self.file_name = file_name
        self.file_object = StringIO(file_content) if isinstance(file_content, str) else BytesIO(file_content)

    def read(self, *args, **kwargs):
        return self.file_object.read(*args, **kwargs)

    def seek(self, *args, **kwargs):
        return self.file_object.seek(*args, **kwargs)

    def tell(self, *args, **kwargs):
        return self.file_object.tell(*args, **kwargs)

    def close(self):
        return self.file_object.close()

def get_s3_file_object(bucket_name, key):
    s3_client = boto3.client('s3')
    try:
        # 下载 S3 对象内容
        response = s3_client.get_object(Bucket=bucket_name, Key=key)
        file_content = response['Body'].read()
        
        # 获取文件名
        file_name = key.split('/')[-1]
        
        # 返回自定义文件对象
        return S3FileObject(file_content, file_name)

    except Exception as e:
        print(f"Error reading S3 object: {e}")
        return None

# 示例使用
bucket_name = 'your-bucket-name'
key = 'your-file-key'

s3_file_object = get_s3_file_object(bucket_name, key)
if s3_file_object:
    print(f"Processing file: {s3_file_object.file_name}")
    content = s3_file_object.read()
    print(content)

    # 将文件对象传递给眼图绘图包
    # eye_diagram_plot(s3_file_object)  # 假设这是眼图绘图包的函数

解释

  1. S3FileObject
    • 包含文件内容和文件名。
    • 使用 StringIOBytesIO 创建一个文件对象,以便支持文本和二进制内容。
    • 实现 readseektellclose 方法,使其行为类似于文件对象。
  2. get_s3_file_object() 函数
    • 使用 boto3 获取 S3 对象内容。
    • 读取 S3 对象内容。
    • 获取文件名(通过拆分 S3 键)。
    • 创建并返回自定义的 S3FileObject 实例。
  3. 示例使用
    • 指定 S3 存储桶名称和文件键。
    • 调用 get_s3_file_object() 函数获取自定义文件对象。
    • 读取文件内容并打印。
    • 将自定义文件对象传递给眼图绘图包的函数(假设眼图绘图包的函数能够处理文件对象)。

注意事项

  • 文件内容类型:根据文件内容是文本还是二进制,分别使用 StringIOBytesIO
  • 自定义文件对象:确保自定义文件对象实现了调用方所需的所有文件方法。
  • 异常处理:在实际应用中,添加更多的异常处理逻辑,以应对可能的错误情况。

在 Django 中,你可以使用 boto3 来获取 S3 上的文件,然后将其以 Blob 的形式返回给前端进行存储或其他操作。下面是一个示例,展示如何实现这个功能。

实现步骤

  1. 从 S3 获取文件内容:使用 boto3 获取文件内容。
  2. 将文件内容返回为 Blob:将文件内容以 application/octet-stream 的形式通过 Django 的 HttpResponse 返回给前端。
  3. 前端处理 Blob:前端可以使用 JavaScript 将 Blob 保存为文件或进行其他处理。

后端代码示例

import boto3
from django.http import HttpResponse
from django.views import View

class S3FileDownloadView(View):
    def get(self, request, *args, **kwargs):
        bucket_name = 'your-bucket-name'
        key = 'your-file-key'
        s3_client = boto3.client('s3')
        
        try:
            # 从 S3 获取文件内容
            response = s3_client.get_object(Bucket=bucket_name, Key=key)
            file_content = response['Body'].read()
            file_name = key.split('/')[-1]
            
            # 将文件内容以 Blob 形式返回
            response = HttpResponse(file_content, content_type='application/octet-stream')
            response['Content-Disposition'] = f'attachment; filename={file_name}'
            return response
        
        except Exception as e:
            return HttpResponse(f"Error retrieving file: {e}", status=500)

# urls.py 中的配置
from django.urls import path
from .views import S3FileDownloadView

urlpatterns = [
    path('download-file/', S3FileDownloadView.as_view(), name='download_file'),
]

前端代码示例

在前端,你可以使用 JavaScript fetch 函数来获取 Blob 并处理它。

function downloadS3File() {
    fetch('/download-file/')
        .then(response => response.blob())
        .then(blob => {
            // 创建一个下载链接
            const url = window.URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = 'filename_from_s3'; // 可以使用后端传递的文件名
            document.body.appendChild(a);
            a.click();
            a.remove();
            window.URL.revokeObjectURL(url);
        })
        .catch(error => {
            console.error('Error downloading file:', error);
        });
}

解释

  1. 后端(Django)
    • S3FileDownloadView:这是一个 Django 视图,用于从 S3 获取文件内容并返回为 Blob
    • HttpResponse:使用 HttpResponse 将文件内容以 application/octet-stream 返回,并设置 Content-Disposition 以提示浏览器下载文件。
  2. 前端(JavaScript)
    • fetch:使用 fetch 获取从 Django 视图返回的文件内容。
    • blob():将响应转换为 Blob
    • 创建下载链接:使用 window.URL.createObjectURL(blob) 创建一个下载链接,并触发下载操作。

注意事项

  • 文件大小:对于非常大的文件,请确保后端能够处理大文件的流式传输,前端也应该能够处理文件下载的延迟。
  • CORS 配置:如果你的前端和后端不在同一个域名下,请确保已经正确配置了跨域资源共享(CORS)。
  • 异常处理:在实际应用中,前后端都需要更详细的异常处理逻辑,以应对可能的错误。

如果你已经获取了 S3 文件的 URL(例如通过生成一个预签名 URL),并且希望通过这个 URL 下载文件然后将其以 Blob 形式返回给前端,可以按以下步骤进行:

实现步骤

  1. 通过 URL 下载文件:使用 requests 库从 S3 的 URL 下载文件。
  2. 将文件内容返回为 Blob:将下载的文件内容以 application/octet-stream 的形式通过 Django 的 HttpResponse 返回给前端。
  3. 前端处理 Blob:前端可以使用 JavaScript 将 Blob 保存为文件或进行其他处理。

后端代码示例

import requests
from django.http import HttpResponse
from django.views import View

class DownloadFromUrlView(View):
    def get(self, request, *args, **kwargs):
        file_url = 'https://your-s3-url'  # 替换为实际的 S3 文件 URL

        try:
            # 通过 URL 下载文件
            response = requests.get(file_url)
            response.raise_for_status()  # 如果请求失败,抛出异常
            
            # 获取文件名(可以从 URL 中提取或其他方式获取)
            file_name = file_url.split('/')[-1]

            # 将文件内容以 Blob 形式返回
            return HttpResponse(response.content, content_type='application/octet-stream', headers={
                'Content-Disposition': f'attachment; filename={file_name}'
            })
        
        except requests.RequestException as e:
            return HttpResponse(f"Error retrieving file: {e}", status=500)

# urls.py 中的配置
from django.urls import path
from .views import DownloadFromUrlView

urlpatterns = [
    path('download-from-url/', DownloadFromUrlView.as_view(), name='download_from_url'),
]

前端代码示例

在前端,你可以使用 JavaScript fetch 函数来获取 Blob 并处理它:

function downloadFileFromUrl() {
    fetch('/download-from-url/')
        .then(response => response.blob())
        .then(blob => {
            // 创建一个下载链接
            const url = window.URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = 'filename_from_url'; // 可以使用后端传递的文件名
            document.body.appendChild(a);
            a.click();
            a.remove();
            window.URL.revokeObjectURL(url);
        })
        .catch(error => {
            console.error('Error downloading file:', error);
        });
}

解释

  1. 后端(Django)
    • DownloadFromUrlView:这是一个 Django 视图,用于通过提供的 URL 下载文件并返回为 Blob
    • requests:使用 requests 库从 S3 文件 URL 下载文件内容。
    • HttpResponse:使用 HttpResponse 将文件内容以 application/octet-stream 返回,并设置 Content-Disposition 以提示浏览器下载文件。
  2. 前端(JavaScript)
    • fetch:使用 fetch 从 Django 视图获取文件内容。
    • blob():将响应转换为 Blob
    • 创建下载链接:使用 window.URL.createObjectURL(blob) 创建一个下载链接,并触发下载操作。

注意事项

  • 文件大小:确保 Django 服务器和前端能够处理大文件的下载和传输。
  • CORS 配置:如果你的前端和后端不在同一个域名下,请确保正确配置了跨域资源共享(CORS)。
  • 异常处理:在实际应用中,前后端都应包含更详细的异常处理逻辑,以应对可能的错误。