如何将file upload到大于5 MB(大约)的Amazon S3(官方SDK)?

我正在使用最新版本的Amazon S3 SDK(1.0.14.1)来创build备份工具。 到目前为止,如果我上传的文件的大小低于5 MB,那么一切工作正常,但是当任何文件大于5 MB时,上传将失败,出现以下exception:

System.Net.WebException:请求被中止:请求被取消。 —> System.IO.IOException:写入所有字节之前无法closuresstream。 在System.Net.ConnectStream.CloseInternal(布尔internalCall,布尔中止)—结束内部exception堆栈跟踪—在Amazon.S3.AmazonS3Client.ProcessRequestError(String actionName,HttpWebRequest请求,WebException我们,HttpWebResponse errorResponse,stringrequestAddr ,Amazon.S3.AmazonS3Client.Invoke [T](S3Request userRequest)在Amazon.S3.AmazonS3Client.PutObject(PutObjectRequest请求)上的WebHeaderCollection&respHdrs,typest).StoModule.UploadFile(String sourceFileName,String destinationFileName)in W: \ code \ AutoBackupTool \ BackupToolkit \ S3Module.cs:W:\ code \ AutoBackupTool \ BackupToolkit \ S3Module.cs中的BackupToolkit.S3Module.UploadFiles(String sourceDirectory)中的第88行:第108行

:5 MB大致是失败的边界,可以稍微低一点或者更高

我假设连接超时,并且在file upload完成之前stream正在被自动closures。

我试图find一种方法来设置一个很长的超时(但我无法在AmazonS3AmazonS3Configfind选项)。

任何关于如何增加超时的想法(就像我可以使用的应用程序范围设置)还是与超时问题无关?


码:

 var s3Client = AWSClientFactory.CreateAmazonS3Client(AwsAccessKey, AwsSecretKey); var putObjectRequest = new PutObjectRequest { BucketName = Bucket, FilePath = sourceFileName, Key = destinationFileName, MD5Digest = md5Base64, GenerateMD5Digest = true }; using (var upload = s3Client.PutObject(putObjectRequest)) { } 

更新回答:

我最近更新了一个使用Amazon AWS .NET SDK的项目(版本1.4.1.0 ),在这个版本中有两个改进,当我在这里写下原始答案时,这个改进是不存在的。

  1. 您现在可以将Timeout设置为-1 ,以便对放置操作有无限的时间限制。
  2. 现在PutObjectRequest上有一个名为ReadWriteTimeout的额外属性,它可以设置(以毫秒为单位)到与整个put操作级别相反的stream读/写级别的超时。

所以我现在的代码如下所示:

 var putObjectRequest = new PutObjectRequest { BucketName = Bucket, FilePath = sourceFileName, Key = destinationFileName, MD5Digest = md5Base64, GenerateMD5Digest = true, Timeout = -1, ReadWriteTimeout = 300000 // 5 minutes in milliseconds }; 

原始答案:


我设法弄清楚答案

在发布问题之前,我已经探索了AmazonS3AmazonS3Config但不是PutObjectRequest

PutObjectRequest里面有一个Timeout属性(以毫秒为单位)。 我已经成功地使用它来上传较大的文件(注意:将其设置为0不会消除超时,您需要指定一个毫秒的正数…我已经走了1个小时)。

这工作正常:

 var putObjectRequest = new PutObjectRequest { BucketName = Bucket, FilePath = sourceFileName, Key = destinationFileName, MD5Digest = md5Base64, GenerateMD5Digest = true, Timeout = 3600000 }; 

我一直有类似的问题,并开始使用TransferUtility类来执行多部分上传。

此刻此代码正在工作。 当超时设置太低,我确实有问题!

  var request = new TransferUtilityUploadRequest() .WithBucketName(BucketName) .WithFilePath(sourceFile.FullName) .WithKey(key) .WithTimeout(100 * 60 * 60 * 1000) .WithPartSize(10 * 1024 * 1024) .WithSubscriber((src, e) => { Console.CursorLeft = 0; Console.Write("{0}: {1} of {2} ", sourceFile.Name, e.TransferredBytes, e.TotalBytes); }); utility.Upload(request); 

正如我input这个,我有一个4GB的上传发生,它已经比以往任何时候都更进一步!

适用于.NET的AWS开发工具包有两个与Amazon S3配合使用的主要API。它们都可以在S3上上传大小文件。

1.低级API:

低级API使用与SDK中其他服务底层API相同的模式。有一个名为AmazonS3Client的客户机对象,它实现了IAmazonS3接口。它包含了S3公开的每个服务操作的方法。

命名空间: Amazon.S3,Amazon.S3.Model

 // Step 1 : AmazonS3Config s3Config = new AmazonS3Config(); s3Config.RegionEndpoint = GetRegionEndPoint(); // Step 2 : using(var client = new AmazonS3Client(My_AWSAccessKey, My_AWSSecretKey, s3Config) ) { // Step 3 : PutObjectRequest request = new PutObjectRequest(); request.Key = My_key; request.InputStream = My_fileStream; request.BucketName = My_BucketName; // Step 4 : Finally place object to S3 client.PutObject(request); } 

2. TransferUtility 🙁我会build议使用这个API)

TransferUtility运行在低级API之上。 为了把对象放到S3中,它是处理S3最常见用法的一个简单的接口。 最大的好处就是放置物体。 例如,TransferUtility检测文件是否很大,并切换到分段上传模式。

命名空间: Amazon.S3.Transfer

 // Step 1 : Create "Transfer Utility" (replacement of old "Transfer Manager") TransferUtility fileTransferUtility = new TransferUtility(new AmazonS3Client(Amazon.RegionEndpoint.USEast1)); // Step 2 : Create Request object TransferUtilityUploadRequest uploadRequest = new TransferUtilityUploadRequest { BucketName = My_BucketName, FilePath = My_filePath, Key = My_keyName }; // Step 3 : Event Handler that will be automatically called on each transferred byte uploadRequest.UploadProgressEvent += new EventHandler<UploadProgressArgs> (uploadRequest_UploadPartProgressEvent); static void uploadRequest_UploadPartProgressEvent(object sender, UploadProgressArgs e) { Console.WriteLine("{0}/{1}", e.TransferredBytes, e.TotalBytes); } // Step 4 : Hit upload and send data to S3 fileTransferUtility.Upload(uploadRequest); 

Nick Randell对此有了正确的想法,对于他的post来说,这里还有另一个例子,提供了一些替代的事件处理方法,以及一个获取上传文件的完成百分比的方法:

  private static string WritingLargeFile(AmazonS3 client, int mediaId, string bucketName, string amazonKey, string fileName, string fileDesc, string fullPath) { try { Log.Add(LogTypes.Debug, mediaId, "WritingLargeFile: Create TransferUtilityUploadRequest"); var request = new TransferUtilityUploadRequest() .WithBucketName(bucketName) .WithKey(amazonKey) .WithMetadata("fileName", fileName) .WithMetadata("fileDesc", fileDesc) .WithCannedACL(S3CannedACL.PublicRead) .WithFilePath(fullPath) .WithTimeout(100 * 60 * 60 * 1000) //100 min timeout .WithPartSize(5 * 1024 * 1024); // Upload in 5MB pieces request.UploadProgressEvent += new EventHandler<UploadProgressArgs>(uploadRequest_UploadPartProgressEvent); Log.Add(LogTypes.Debug, mediaId, "WritingLargeFile: Create TransferUtility"); TransferUtility fileTransferUtility = new TransferUtility(ConfigurationManager.AppSettings["AWSAccessKey"], ConfigurationManager.AppSettings["AWSSecretKey"]); Log.Add(LogTypes.Debug, mediaId, "WritingLargeFile: Start Upload"); fileTransferUtility.Upload(request); return amazonKey; } catch (AmazonS3Exception amazonS3Exception) { if (amazonS3Exception.ErrorCode != null && (amazonS3Exception.ErrorCode.Equals("InvalidAccessKeyId") || amazonS3Exception.ErrorCode.Equals("InvalidSecurity"))) { Log.Add(LogTypes.Debug, mediaId, "Please check the provided AWS Credentials."); } else { Log.Add(LogTypes.Debug, mediaId, String.Format("An error occurred with the message '{0}' when writing an object", amazonS3Exception.Message)); } return String.Empty; //Failed } } private static Dictionary<string, int> uploadTracker = new Dictionary<string, int>(); static void uploadRequest_UploadPartProgressEvent(object sender, UploadProgressArgs e) { TransferUtilityUploadRequest req = sender as TransferUtilityUploadRequest; if (req != null) { string fileName = req.FilePath.Split('\\').Last(); if (!uploadTracker.ContainsKey(fileName)) uploadTracker.Add(fileName, e.PercentDone); //When percentage done changes add logentry: if (uploadTracker[fileName] != e.PercentDone) { uploadTracker[fileName] = e.PercentDone; Log.Add(LogTypes.Debug, 0, String.Format("WritingLargeFile progress: {1} of {2} ({3}%) for file '{0}'", fileName, e.TransferredBytes, e.TotalBytes, e.PercentDone)); } } } public static int GetAmazonUploadPercentDone(string fileName) { if (!uploadTracker.ContainsKey(fileName)) return 0; return uploadTracker[fileName]; } 

在这里看到这个主题如何上传一个文件到亚马逊S3超级容易使用C#包括一个演示项目下载。 它是使用AWS sdk .net 3.5(及更高版本)的高级别,可以使用以下代码来使用它:

  // preparing our file and directory names string fileToBackup = @"d:\mybackupFile.zip" ; // test file string myBucketName = "mys3bucketname"; //your s3 bucket name goes here string s3DirectoryName = "justdemodirectory"; string s3FileName = @"mybackupFile uploaded in 12-9-2014.zip"; AmazonUploader myUploader = new AmazonUploader(); myUploader.sendMyFileToS3(fileToBackup, myBucketName, s3DirectoryName, s3FileName);