Amazon S3 通过 .NET SDK 创建文件夹与通过管理控制台创建文件夹

问题描述 投票:0回答:4

我正在尝试确定我的 Amazon S3 存储桶上是否存在某个文件夹,如果不存在,我想创建它。

目前我可以使用 .NET SDK 创建文件夹,如下所示:

        public void CreateFolder(string bucketName, string folderName)
    {
        var folderKey = folderName + "/"; //end the folder name with "/"

        var request = new PutObjectRequest();

        request.WithBucketName(bucketName);

        request.StorageClass = S3StorageClass.Standard;
        request.ServerSideEncryptionMethod = ServerSideEncryptionMethod.None;

        //request.CannedACL = S3CannedACL.BucketOwnerFullControl;

        request.WithKey(folderKey);

        request.WithContentBody(string.Empty);

        S3Response response = m_S3Client.PutObject(request);

    }

现在,当我尝试使用此代码查看该文件夹是否存在时:

        public bool DoesFolderExist(string key, string bucketName)
    {
        try
        {
            S3Response response = m_S3Client.GetObjectMetadata(new GetObjectMetadataRequest()
               .WithBucketName(bucketName)
               .WithKey(key));

            return true;
        }
        catch (Amazon.S3.AmazonS3Exception ex)
        {
            if (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
                return false;

            //status wasn't not found, so throw the exception
            throw;
        }
    }

找不到该文件夹。奇怪的是,如果我使用 AWS 管理控制台创建文件夹,“DoesFolderExist”方法可以看到它。

我不确定这是否是 ACL/IAM 的问题,但不确定如何解决此问题。

c# .net amazon-s3 amazon-web-services
4个回答
18
投票

您的代码实际上对我有用,但有一些事情您需要注意。

据我了解,Amazon S3 没有文件夹的概念,但各个客户端可能会像显示文件夹一样显示 S3 对象。因此,如果您创建一个名为 A/B 的对象,那么客户端可能会显示它,就好像它是名为 A 的文件夹内名为 B 的对象一样。这很直观,似乎已成为标准,但模拟空文件夹不会出现有一个标准。

例如,我使用你的方法创建了一个名为 Test 的文件夹,然后实际上最终创建了一个名为 Test/ 的对象。但我在 AWS Explorer(即 Visual Studio 的插件)中创建了一个名为 Test2 的文件夹,它最终创建了一个名为 Test2/Test2_$folder$ 的对象 (AWS Explorer 会将 Test 和 Test2 显示为文件夹)

这意味着您不需要在使用“文件夹”之前创建它,这可能意味着您不需要DoesFolderExist 方法。

正如我提到的,我尝试了您的代码,它可以工作并找到它创建的 Test 文件夹,但必须调整密钥才能找到由 AWS Explorer 创建的文件夹,即

DoesFolderExist("Test/" , bucketName); // Returns true DoesFolderExist("Test2/" , bucketName); // Returns false DoesFolderExist("Test2/Test2_$folder$", bucketName); // Returns true

因此,如果您仍然想要使用DoesFolderExist方法,那么仅查找以folderName +“/”开头的任何对象可能会更安全,即类似

ListObjectsRequest request = new ListObjectsRequest(); request.BucketName = bucketName ; request.WithPrefix(folderName + "/"); request.MaxKeys = 1; using (ListObjectsResponse response = m_S3Client.ListObjects(request)) { return (response.S3Objects.Count > 0); }
    

2
投票
刚刚使用 AWS .Net SDK 版本 2 将上述代码重构为异步方法:

public async Task CreateFoldersAsync(string bucketName, string path) { path = path.EnsureEndsWith('/'); IAmazonS3 client = new AmazonS3Client(YOUR.AccessKeyId, YOUR.SecretAccessKey, RegionEndpoint.EUWest1); var findFolderRequest = new ListObjectsV2Request(); findFolderRequest.BucketName = bucketName; findFolderRequest.Prefix = path; findFolderRequest.MaxKeys = 1; ListObjectsV2Response findFolderResponse = await client.ListObjectsV2Async(findFolderRequest); if (findFolderResponse.S3Objects.Any()) { return; } PutObjectRequest request = new PutObjectRequest() { BucketName = bucketName, StorageClass = S3StorageClass.Standard, ServerSideEncryptionMethod = ServerSideEncryptionMethod.None, Key = path, ContentBody = string.Empty }; // add try catch in case you have exceptions shield/handling here PutObjectResponse response = await client.PutObjectAsync(request); }
    

1
投票
ListObjectsRequest findFolderRequest = new ListObjectsRequest(); findFolderRequest.BucketName = bucketName; findFolderRequest.Prefix = path; ListObjectsResponse findFolderResponse = s3Client.ListObjects(findFolderRequest); Boolean folderExists = findFolderResponse.S3Objects.Any();

路径可以是“images/40/”之类的东西。 使用上面的代码可以检查bucket下是否存在所谓的“images/40/”文件夹。

但是Amazon S3数据模型没有文件夹的概念。当您尝试将图像或文件复制到特定路径时,如果这个所谓的文件夹不存在,它将自动创建作为该文件或图像的键名的一部分。因此,你实际上不需要检查这个文件夹是否存在。

来自 docs.aws.amazon.com 的非常重要的信息:Amazon S3 数据模型是扁平结构:您创建一个存储桶,存储桶存储对象。没有子存储桶或子文件夹的层次结构;但是,您可以像 Amazon S3 控制台一样使用键名称前缀和分隔符来推断逻辑层次结构。

http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html


0
投票
提供一些C#示例

using Amazon.S3.Transfer; using Amazon.S3; using Amazon; using System; using System.Linq; using System.Threading.Tasks; using System.IO; using System.Configuration; using Amazon.S3.Model; namespace awss3Uploader { internal class Program { static readonly string bucketName = ConfigurationManager.AppSettings["S3_BucketName"]; static async Task Main(string[] args) { try { RegionEndpoint region = RegionEndpoint.GetBySystemName(ConfigurationManager.AppSettings["S3_RegionName"]); var awsAccessKeyId = ConfigurationManager.AppSettings["S3_awsAccessKeyId"]; var awsSecretAccessKey = ConfigurationManager.AppSettings["S3_awsSecretAccessKey"]; var s3Client = new AmazonS3Client(awsAccessKeyId, awsSecretAccessKey, region); await UploadFile(s3Client); } catch (Exception ex) { Console.WriteLine(ex.InnerException.Message); Console.WriteLine(ex.StackTrace); } Console.ReadLine(); } static async Task UploadFile(AmazonS3Client s3Client) { var localFolderPath = ConfigurationManager.AppSettings["S3_LocalUploadFolderPath"]; string remoteFolderPrefix = ConfigurationManager.AppSettings["S3_FolderPrefix"]; var fileTransferUtility = new TransferUtility(s3Client); DirectoryInfo directoryInfo= new DirectoryInfo(localFolderPath); var allLocalUploadFiles = directoryInfo.GetFiles(); if (allLocalUploadFiles.Count()<1) { Console.WriteLine($"No files to upload"); } foreach (var item in allLocalUploadFiles) { Console.WriteLine($"Uploading file {item.Name}"); await fileTransferUtility.UploadAsync(item.FullName,bucketName, remoteFolderPrefix+"/"+item.Name); Console.WriteLine($"File Uploaded"); Console.WriteLine($"File removing from local"); System.IO.File.Delete(item.FullName); Console.WriteLine($"File removed from local"); } var allFiles = s3Client.ListObjectsAsync(bucketName,remoteFolderPrefix+"/").Result.S3Objects; Console.WriteLine($"Below files are available now, count {allFiles.Count}"); foreach (var file in allFiles) { Console.WriteLine(file.Key); } //DownloadS3Files(fileTransferUtility, localFolderPath+"TestS3\\"); Console.WriteLine("Press a key to exit.."); Console.ReadKey(); } private static void DownloadS3Files(TransferUtility s3Transfer, string LocalFolderPath) { string remoteFolderPrefix = ConfigurationManager.AppSettings["S3_FolderPrefix"]; string bucketName = ConfigurationManager.AppSettings["S3_BucketName"]; var allFilesInS3 = s3Transfer.S3Client.ListObjects(bucketName, remoteFolderPrefix).S3Objects; Console.WriteLine("S3 total files " + allFilesInS3.Count); foreach (var file in allFilesInS3) { var fileNameparts = file.Key.Split('/'); var filename = fileNameparts[fileNameparts.Length - 1]; if (filename == string.Empty) { Console.WriteLine("S3 invalid file :" + file.Key); continue; } Console.WriteLine("S3 downloading file :" + file.Key); s3Transfer.Download(LocalFolderPath + filename, bucketName, file.Key); Console.WriteLine("S3 download complete"); Console.WriteLine("S3 removing file :" + file.Key); s3Transfer.S3Client.DeleteObject(bucketName, file.Key); Console.WriteLine("S3 file removed"); } } public static bool DoesFolderExist(AmazonS3Client s3Client,string bucketName,string FolderPath) { ListObjectsRequest findFolderRequest = new ListObjectsRequest(); findFolderRequest.BucketName = bucketName; findFolderRequest.Prefix = FolderPath; ListObjectsResponse findFolderResponse = s3Client.ListObjects(findFolderRequest); Boolean folderExists = findFolderResponse.S3Objects.Any(); return folderExists; } private static async Task ListBucketsAsync(AmazonS3Client s3Client) { var allBucket = s3Client.ListBucketsAsync().Result.Buckets; foreach (var item in allBucket) { Console.WriteLine(item.BucketName); try { var allFiles = s3Client.ListObjectsAsync(item.BucketName, "").Result.S3Objects; foreach (var file in allFiles) { Console.WriteLine(file.Key); } } catch (Exception ex) { Console.WriteLine(ex.InnerException.Message); } } } } }
    
© www.soinside.com 2019 - 2024. All rights reserved.