导入 AWS SDK for Swift
确保 Swift 5.7 或更高版本,以及 OpenSSL v1.x 已经被安装。
AWS SDK for Swift 支持以下平台:
- iOS & iPadOS 13.0 或更高版本
- macOS 10.15 或更高版本
- Ubuntu Linux 16.04 LTS 或更高版本
- Amazon Linux 2 或更高版本
初始化 Swift 项目
swift package init --type executable
添加 AWS SDK for Swift 包,这里给出 Package.swift
的案例
// swift-tools-version:5.5
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "aws-swift-sdk-test-examples",
dependencies: [
.package(
url: "https://github.com/awslabs/aws-sdk-swift",
from: "0.36.0"
)
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.executableTarget(
name: "aws-swift-sdk-test-examples",
dependencies: [
.product(name: "AWSS3", package: "aws-sdk-swift"),
.product(name: "AWSSTS", package: "aws-sdk-swift")],
path: "Sources")
]
)
对于之后的每个代码示例,将代码创建在 Sources/entry.swift
后,执行
swift run
即可执行代码。
对象上传
获取客户端上传 URL
创建 Sources/entry.swift
import AWSClientRuntime
import AWSS3
@main
struct Main {
static func main() async throws {
let config = try await S3Client.S3ClientConfiguration()
config.credentialsProvider = try StaticCredentialsProvider(Credentials(
accessKey: "<QiniuAccessKey>",
secret: "<QiniuSecretKey>"
))
config.region = "cn-east-1" // 华东-浙江区 region id
config.endpoint = "https://s3.cn-east-1.qiniucs.com" // 华东-浙江区 endpoint
let uploadRequest = PutObjectInput(
bucket: "<Bucket>",
key: "<Key>"
)
let url = try await uploadRequest.presignURL(config: config, expiration: 3600)
print("\(String(describing: url))")
}
}
这段代码将生成一个经过预先签名的客户端上传 URL,有效期为 1 小时,客户端可以在过期时间内对该 URL 发送 HTTP PUT 请求将文件上传。
以下是用 curl 上传文件的案例:
curl -X PUT --upload-file "<path/to/file>" "<presigned url>"
服务器端直传
单请求上传(文件)
创建 Sources/entry.swift
import Foundation
import ClientRuntime
import AWSClientRuntime
import AWSS3
@main
struct Main {
static func main() async throws {
let config = try await S3Client.S3ClientConfiguration()
config.credentialsProvider = try StaticCredentialsProvider(Credentials(
accessKey: "<QiniuAccessKey>",
secret: "<QiniuSecretKey>"
))
config.region = "cn-east-1" // 华东-浙江区 region id
config.endpoint = "https://s3.cn-east-1.qiniucs.com" // 华东-浙江区 endpoint
let client = S3Client(config: config)
guard let file = FileHandle(forReadingAtPath: "<path/to/upload>") else {
return
}
let response = try await client.putObject(input: PutObjectInput(
body: ByteStream.from(fileHandle: file),
bucket: "<Bucket>",
key: "<Key>"
))
print("ETag: \(String(describing: response.eTag))")
}
}
单请求上传(数据流)
创建 Sources/entry.swift
import Foundation
import ClientRuntime
import AWSClientRuntime
import AWSS3
@main
struct Main {
static func main() async throws {
let config = try await S3Client.S3ClientConfiguration()
config.credentialsProvider = try StaticCredentialsProvider(Credentials(
accessKey: "<QiniuAccessKey>",
secret: "<QiniuSecretKey>"
))
config.region = "cn-east-1" // 华东-浙江区 region id
config.endpoint = "https://s3.cn-east-1.qiniucs.com" // 华东-浙江区 endpoint
let client = S3Client(config: config)
let response = try await client.putObject(input: PutObjectInput(
body: ByteStream.data("Hello from Qiniu S3!".data(using: .utf8)),
bucket: "<Bucket>",
key: "<Key>"
))
print("ETag: \(String(describing: response.eTag))")
}
}
分片上传(文件)
创建 Sources/entry.swift
import Foundation
import ClientRuntime
import AWSClientRuntime
import AWSS3
@main
struct Main {
static func main() async throws {
let config = try await S3Client.S3ClientConfiguration()
config.credentialsProvider = try StaticCredentialsProvider(Credentials(
accessKey: "<QiniuAccessKey>",
secret: "<QiniuSecretKey>"
))
config.region = "cn-east-1" // 华东-浙江区 region id
config.endpoint = "https://s3.cn-east-1.qiniucs.com" // 华东-浙江区 endpoint
let client = S3Client(config: config)
guard let file = FileHandle(forReadingAtPath: "<path/to/upload>") else {
return
}
let createMultipartUploadResponse = try await client.createMultipartUpload(input: CreateMultipartUploadInput(
bucket: "<Bucket>",
key: "<Key>"
))
if createMultipartUploadResponse.uploadId == nil {
return
}
let PART_SIZE = 5 * 1024 * 1024 // 分片大小为 5 MB
var parts = [S3ClientTypes.CompletedPart]()
var partNum = 1
// 这里给出的案例是串行分片上传。可以自行改造成并行分片上传以进一步提升上传速度
while true {
let data = file.readData(ofLength: PART_SIZE)
if data.count == 0 {
break
}
let uploadPartResponse = try await client.uploadPart(input: UploadPartInput(
body: ByteStream.data(data),
bucket: createMultipartUploadResponse.bucket,
key: createMultipartUploadResponse.key,
partNumber: partNum,
uploadId: createMultipartUploadResponse.uploadId
))
if uploadPartResponse.eTag == nil {
return
}
parts.append(S3ClientTypes.CompletedPart(
eTag: uploadPartResponse.eTag,
partNumber: partNum
))
partNum += 1
}
let completeMultipartUploadResponse = try await client.completeMultipartUpload(input: CompleteMultipartUploadInput(
bucket: createMultipartUploadResponse.bucket,
key: createMultipartUploadResponse.key,
multipartUpload: S3ClientTypes.CompletedMultipartUpload(parts: parts),
uploadId: createMultipartUploadResponse.uploadId
))
print("ETag: \(String(describing: completeMultipartUploadResponse.eTag)))")
}
}
对象下载
获取客户端下载 URL
创建 Sources/entry.swift
import AWSClientRuntime
import AWSS3
@main
struct Main {
static func main() async throws {
let config = try await S3Client.S3ClientConfiguration()
config.credentialsProvider = try StaticCredentialsProvider(Credentials(
accessKey: "<QiniuAccessKey>",
secret: "<QiniuSecretKey>"
))
config.region = "cn-east-1" // 华东-浙江区 region id
config.endpoint = "https://s3.cn-east-1.qiniucs.com" // 华东-浙江区 endpoint
let downloadRequest = GetObjectInput(
bucket: "<Bucket>",
key: "<Key>"
)
let url = try await downloadRequest.presignURL(config: config, expiration: 3600)
print("\(String(describing: url))")
}
}
这段代码将生成一个经过预先签名的客户端下载 URL,有效期为 1 小时,客户端可以在过期时间内对该 URL 发送 HTTP GET 请求将文件下载。
以下是用 curl 下载文件的案例:
curl -o "<path/to/download>" "<presigned url>"
服务器端直接下载
创建 Sources/entry.swift
import AWSClientRuntime
import AWSS3
@main
struct Main {
static func main() async throws {
let config = try await S3Client.S3ClientConfiguration()
config.credentialsProvider = try StaticCredentialsProvider(Credentials(
accessKey: "<QiniuAccessKey>",
secret: "<QiniuSecretKey>"
))
config.region = "cn-east-1" // 华东-浙江区 region id
config.endpoint = "https://s3.cn-east-1.qiniucs.com" // 华东-浙江区 endpoint
let client = S3Client(config: config)
let response = try await client.getObject(input: GetObjectInput(
bucket: "<Bucket>",
key: "<Key>"
))
guard let body = response.body,
let data = try await body.readData() else {
return
}
try data.write(to: URL(fileURLWithPath: "<path/to/download>"))
print("ETag: \(String(describing: response.eTag))")
}
}
对象管理
获取对象信息
创建 Sources/entry.swift
import AWSClientRuntime
import AWSS3
@main
struct Main {
static func main() async throws {
let config = try await S3Client.S3ClientConfiguration()
config.credentialsProvider = try StaticCredentialsProvider(Credentials(
accessKey: "<QiniuAccessKey>",
secret: "<QiniuSecretKey>"
))
config.region = "cn-east-1" // 华东-浙江区 region id
config.endpoint = "https://s3.cn-east-1.qiniucs.com" // 华东-浙江区 endpoint
let client = S3Client(config: config)
let response = try await client.headObject(input: HeadObjectInput(
bucket: "<Bucket>",
key: "<Key>"
))
print("ETag: \(String(describing: response.eTag))")
}
}
修改对象 MimeType
创建 Sources/entry.swift
import AWSClientRuntime
import AWSS3
@main
struct Main {
static func main() async throws {
let config = try await S3Client.S3ClientConfiguration()
config.credentialsProvider = try StaticCredentialsProvider(Credentials(
accessKey: "<QiniuAccessKey>",
secret: "<QiniuSecretKey>"
))
config.region = "cn-east-1" // 华东-浙江区 region id
config.endpoint = "https://s3.cn-east-1.qiniucs.com" // 华东-浙江区 endpoint
let client = S3Client(config: config)
let _ = try await client.copyObject(input: CopyObjectInput(
bucket: "<Bucket>",
contentType: "text/plain",
copySource: "/<Bucket>/<Key>",
key: "<Bucket>",
metadataDirective: .replace
))
print("Done")
}
}
修改对象存储类型
创建 Sources/entry.swift
import AWSClientRuntime
import AWSS3
@main
struct Main {
static func main() async throws {
let config = try await S3Client.S3ClientConfiguration()
config.credentialsProvider = try StaticCredentialsProvider(Credentials(
accessKey: "<QiniuAccessKey>",
secret: "<QiniuSecretKey>"
))
config.region = "cn-east-1" // 华东-浙江区 region id
config.endpoint = "https://s3.cn-east-1.qiniucs.com" // 华东-浙江区 endpoint
let client = S3Client(config: config)
let _ = try await client.copyObject(input: CopyObjectInput(
bucket: "<Bucket>",
copySource: "/<Bucket>/<Key>",
key: "<Key>",
metadataDirective: .replace,
storageClass: .glacier
))
print("Done")
}
}
复制对象副本
创建 Sources/entry.swift
import AWSClientRuntime
import AWSS3
@main
struct Main {
static func main() async throws {
let config = try await S3Client.S3ClientConfiguration()
config.credentialsProvider = try StaticCredentialsProvider(Credentials(
accessKey: "<QiniuAccessKey>",
secret: "<QiniuSecretKey>"
))
config.region = "cn-east-1" // 华东-浙江区 region id
config.endpoint = "https://s3.cn-east-1.qiniucs.com" // 华东-浙江区 endpoint
let client = S3Client(config: config)
let _ = try await client.copyObject(input: CopyObjectInput(
bucket: "<ToBucket>",
copySource: "/<FromBucket>/<FromKey>",
key: "<ToKey>",
metadataDirective: .copy
))
print("Done")
}
}
复制对象副本(大于 5GB)
创建 Sources/entry.swift
import Foundation
import ClientRuntime
import AWSClientRuntime
import AWSS3
@main
struct Main {
static func main() async throws {
let config = try await S3Client.S3ClientConfiguration()
config.credentialsProvider = try StaticCredentialsProvider(Credentials(
accessKey: "<QiniuAccessKey>",
secret: "<QiniuSecretKey>"
))
config.region = "cn-east-1" // 华东-浙江区 region id
config.endpoint = "https://s3.cn-east-1.qiniucs.com" // 华东-浙江区 endpoint
let client = S3Client(config: config)
let headObjectResponse = try await client.headObject(input: HeadObjectInput(
bucket: "<FromBucket>",
key: "<FromKey>"
))
let createMultipartUploadResponse = try await client.createMultipartUpload(input: CreateMultipartUploadInput(
bucket: "<ToBucket>",
key: "<ToKey>"
))
if createMultipartUploadResponse.uploadId == nil {
return
}
let PART_SIZE = 5 * 1024 * 1024 // 分片大小为 5 MB
var parts = [S3ClientTypes.CompletedPart]()
var partNum = 1
var copied = 0
// 这里给出的案例是串行分片复制。可以自行改造成并行分片复制以进一步提升复制速度
while copied < headObjectResponse.contentLength! {
let partSize = min(headObjectResponse.contentLength! - copied, PART_SIZE)
let uploadPartCopyResponse = try await client.uploadPartCopy(input: UploadPartCopyInput(
bucket: createMultipartUploadResponse.bucket,
copySource: "/<FromBucket>/<FromKey>",
copySourceRange: "bytes=\(copied)-\(copied+partSize-1)",
key: createMultipartUploadResponse.key,
partNumber: partNum,
uploadId: createMultipartUploadResponse.uploadId
))
if uploadPartCopyResponse.copyPartResult?.eTag == nil {
return
}
parts.append(S3ClientTypes.CompletedPart(
eTag: uploadPartCopyResponse.copyPartResult?.eTag,
partNumber: partNum
))
partNum += 1
copied += partSize
}
let completeMultipartUploadResponse = try await client.completeMultipartUpload(input: CompleteMultipartUploadInput(
bucket: createMultipartUploadResponse.bucket,
key: createMultipartUploadResponse.key,
multipartUpload: S3ClientTypes.CompletedMultipartUpload(parts: parts),
uploadId: createMultipartUploadResponse.uploadId
))
print("ETag: \(String(describing: completeMultipartUploadResponse.eTag)))")
}
}
删除空间中的文件
创建 Sources/entry.swift
import AWSClientRuntime
import AWSS3
@main
struct Main {
static func main() async throws {
let config = try await S3Client.S3ClientConfiguration()
config.credentialsProvider = try StaticCredentialsProvider(Credentials(
accessKey: "<QiniuAccessKey>",
secret: "<QiniuSecretKey>"
))
config.region = "cn-east-1" // 华东-浙江区 region id
config.endpoint = "https://s3.cn-east-1.qiniucs.com" // 华东-浙江区 endpoint
let client = S3Client(config: config)
let _ = try await client.deleteObject(input: DeleteObjectInput(
bucket: "<Bucket>",
key: "<Key>"
))
print("Done")
}
}
获取指定前缀的文件列表
创建 Sources/entry.swift
import AWSClientRuntime
import AWSS3
@main
struct Main {
static func main() async throws {
let config = try await S3Client.S3ClientConfiguration()
config.credentialsProvider = try StaticCredentialsProvider(Credentials(
accessKey: "<QiniuAccessKey>",
secret: "<QiniuSecretKey>"
))
config.region = "cn-east-1" // 华东-浙江区 region id
config.endpoint = "https://s3.cn-east-1.qiniucs.com" // 华东-浙江区 endpoint
let client = S3Client(config: config)
let response = try await client.listObjectsV2(input: ListObjectsV2Input(
bucket: "<Bucket>",
prefix: "<KeyPrefix>"
))
for content in response.contents ?? [] {
print("Key: \(String(describing: content.key))")
print("ETag: \(String(describing: content.eTag))")
}
}
}
批量删除空间中的文件
创建 Sources/entry.swift
import AWSClientRuntime
import AWSS3
@main
struct Main {
static func main() async throws {
let config = try await S3Client.S3ClientConfiguration()
config.credentialsProvider = try StaticCredentialsProvider(Credentials(
accessKey: "<QiniuAccessKey>",
secret: "<QiniuSecretKey>"
))
config.region = "cn-east-1" // 华东-浙江区 region id
config.endpoint = "https://s3.cn-east-1.qiniucs.com" // 华东-浙江区 endpoint
let client = S3Client(config: config)
let _ = try await client.deleteObjects(input: DeleteObjectsInput(
bucket: "<Bucket>",
delete: S3ClientTypes.Delete(objects: [
S3ClientTypes.ObjectIdentifier(key: "<Key1>"),
S3ClientTypes.ObjectIdentifier(key: "<Key2>"),
S3ClientTypes.ObjectIdentifier(key: "<Key3>"),
])
))
print("Done")
}
}
临时安全凭证
创建 Sources/entry.swift
import Foundation
import ClientRuntime
import AwsCommonRuntimeKit
import AWSClientRuntime
import AWSS3
import AWSSTS
struct StsCredentialsProvider: AWSClientRuntime.CredentialsProviding {
private let stsClient: STSClient
private let getFederationTokenInput: GetFederationTokenInput
public init(_ stsClient: STSClient, getFederationTokenInput: GetFederationTokenInput) throws {
self.stsClient = stsClient
self.getFederationTokenInput = getFederationTokenInput
}
func getCredentials() async throws -> AWSClientRuntime.Credentials {
let getFederationTokenOutput = try await self.stsClient.getFederationToken(input: self.getFederationTokenInput)
return AWSClientRuntime.Credentials(
accessKey: getFederationTokenOutput.credentials!.accessKeyId!,
secret: getFederationTokenOutput.credentials!.secretAccessKey!,
expirationTimeout: getFederationTokenOutput.credentials?.expiration,
sessionToken: getFederationTokenOutput.credentials?.sessionToken)
}
}
@main
struct Main {
static func main() async throws {
let stsConfig = try await STSClient.STSClientConfiguration()
stsConfig.credentialsProvider = try StaticCredentialsProvider(Credentials(
accessKey: "<QiniuAccessKey>",
secret: "<QiniuSecretKey>"
))
stsConfig.region = "cn-east-1" // 华东-浙江区 region id
stsConfig.signingRegion = stsConfig.region
stsConfig.endpoint = "https://s3.cn-east-1.qiniucs.com" // 华东-浙江区 endpoint
let stsCredentialsProvider = try StsCredentialsProvider(STSClient(config: stsConfig), getFederationTokenInput: GetFederationTokenInput(
durationSeconds: 3600,
name: "Bob",
policy: "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"Stmt1\",\"Effect\":\"Allow\",\"Action\":[\"*\"],\"Resource\":[\"*\"]}]}"))
let s3Config = try await S3Client.S3ClientConfiguration()
s3Config.credentialsProvider = try AWSClientRuntime.CachedCredentialsProvider(source: stsCredentialsProvider, refreshTime: 0)
s3Config.region = "cn-east-1" // 华东-浙江区 region id
s3Config.signingRegion = s3Config.region
s3Config.endpoint = "https://s3.cn-east-1.qiniucs.com" // 华东-浙江区 endpoint
let client = S3Client(config: s3Config)
// 可以使用这些临时凭证调用 S3 服务
try await client.listBuckets(input: ListBucketsInput()).buckets?.forEach { bucket in
print(bucket.name!)
}
}
}
文档反馈
(如有产品使用问题,请 提交工单)