如何将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一种方法来设置一个很长的超时(但我无法在AmazonS3
或AmazonS3Config
find选项)。
任何关于如何增加超时的想法(就像我可以使用的应用程序范围设置)还是与超时问题无关?
码:
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 ),在这个版本中有两个改进,当我在这里写下原始答案时,这个改进是不存在的。
- 您现在可以将
Timeout
设置为-1
,以便对放置操作有无限的时间限制。 - 现在
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 };
原始答案:
我设法弄清楚答案
在发布问题之前,我已经探索了AmazonS3
和AmazonS3Config
但不是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);