如何用Swift及AZSClient将iOS相册视频上传至Azure Blob Storage
iOS视频上传至Azure Blob Storage(AZSClient实现)
首先得明确:视频文件通常比图片大得多,直接像图片那样取Data上传很容易导致内存飙升甚至崩溃。所以咱们换个更稳妥的思路——先获取视频的本地文件URL,再用分块上传的方式传到Azure Blob,这样既省内存,还支持断点续传。
下面是完整的Swift实现步骤:
1. 获取相册视频的本地URL
从PHAsset获取视频的本地路径,这里用PHAssetResourceManager处理,比直接取Data高效得多:
import Photos func getVideoLocalURL(from asset: PHAsset, completion: @escaping (URL?) -> Void) { guard asset.mediaType == .video else { completion(nil) return } let resources = PHAssetResource.assetResources(for: asset) guard let videoResource = resources.first(where: { $0.type == .video }) else { completion(nil) return } let tempDir = FileManager.default.temporaryDirectory let tempFileURL = tempDir.appendingPathComponent("\(UUID().uuidString).mov") let options = PHAssetResourceRequestOptions() options.isNetworkAccessAllowed = true // 允许从iCloud下载视频 PHAssetResourceManager.default().writeData(for: videoResource, toFile: tempFileURL, options: options) { error in if let error = error { print("导出视频失败: \(error.localizedDescription)") completion(nil) } else { completion(tempFileURL) } } }
2. 初始化Azure Blob相关对象
这一步和图片上传逻辑一致,先拿到AZSCloudBlockBlob实例:
import AzureStorageBlob func getAzureBlockBlob() -> AZSCloudBlockBlob? { // 替换成你的Azure存储账号连接字符串 guard let storageAccount = AZSCloudStorageAccount(fromConnectionString: "你的Azure存储连接字符串") else { print("存储账号初始化失败") return nil } let blobClient = storageAccount.getBlobClient() // 替换成你的容器名称 let container = blobClient.containerReference(fromName: "你的容器名称") // 替换成Blob中要保存的文件名 let blobName = "uploaded_video_\(UUID().uuidString).mov" return container.blockBlobReference(fromName: blobName) }
3. 分块上传视频到Azure Blob
分块上传是大文件上传的最佳实践,Azure Blob支持最大100MB的分块,这里咱们用4MB作为分块大小(可按需调整):
func uploadVideoToAzure(blob: AZSCloudBlockBlob, localURL: URL, completion: @escaping (Error?) -> Void) { let fileHandle: FileHandle do { fileHandle = try FileHandle(forReadingFrom: localURL) } catch { completion(error) return } defer { fileHandle.closeFile() } let fileSize = try! FileManager.default.attributesOfItem(atPath: localURL.path)[.size] as! UInt64 let blockSize: UInt64 = 4 * 1024 * 1024 // 4MB分块 let blockCount = (fileSize + blockSize - 1) / blockSize // 计算总块数 var blockIDs: [String] = [] // 逐个上传分块 for blockIndex in 0..<blockCount { let offset = blockIndex * blockSize let readSize = min(blockSize, fileSize - offset) fileHandle.seek(toFileOffset: offset) let blockData = fileHandle.readData(ofLength: Int(readSize)) // 生成唯一的block ID let blockID = "\(UUID().uuidString)".data(using: .utf8)!.base64EncodedString() blockIDs.append(blockID) // 上传单个分块 blob.createBlock(withId: blockID, from: blockData) { error in if let error = error { completion(error) return } // 所有分块上传完成后,提交块列表 if blockIndex == blockCount - 1 { blob.commitBlockList(blockIDs) { error in completion(error) } } } } }
4. 整合流程调用
把上面的方法串起来,完整调用示例:
// 假设你已经获取到目标PHAsset实例 let targetVideoAsset: PHAsset = ... getVideoLocalURL(from: targetVideoAsset) { localURL in guard let localURL = localURL else { print("获取视频本地URL失败") return } guard let blob = getAzureBlockBlob() else { print("Azure Blob实例初始化失败") return } uploadVideoToAzure(blob: blob, localURL: localURL) { error in if let error = error { print("视频上传失败: \(error.localizedDescription)") } else { print("视频上传成功!Blob URL: \(blob.absoluteString)") // 上传完成后可删除临时文件 try? FileManager.default.removeItem(at: localURL) } } }
注意事项
- 权限配置:别忘了在
Info.plist中添加NSPhotoLibraryUsageDescription(iOS13及以下)或NSPhotoLibraryAddUsageDescription/NSPhotoLibraryLimitedUsageDescription(iOS14+),否则无法访问相册。 - 分块大小调整:视频特别大时可适当增大分块(最大100MB)减少请求次数;网络不稳定时建议用小分块,降低重试成本。
- 断点续传:如果需要断点续传,可先调用
blob.downloadBlockList()获取已上传的块ID,跳过这些块继续上传未完成部分。 - 错误处理:示例简化了错误处理,实际开发中要针对网络错误、Azure权限错误、文件读取错误等做细致处理。
内容的提问来源于stack exchange,提问作者Rizwan
相关产品推荐
相关产品推荐

