对象存储

  • 对象存储 > 使用指南 > 开发指南 > AWS S3 兼容 > 兼容 SDK 示例 > AWS SDK for Swift

    AWS SDK for Swift

    最近更新时间: 2024-02-19 17:03:58

    导入 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!) } } } 
    以上内容是否对您有帮助?