Как загрузить в Amazon S3 (официальный SDK) файлы размером более 5 МБ (приблизительно)? - PullRequest
36 голосов
/ 06 октября 2010

Я использую последнюю версию официального пакета Amazon S3 SDK (1.0.14.1) для создания инструмента резервного копирования.Пока все работает правильно, если размер файла, который я загружаю, меньше 5 МБ, но когда любой из файлов превышает 5 МБ, загрузка завершается неудачно со следующим исключением:

System.Net.WebException: запрос был прерван: запрос был отменен.---> System.IO.IOException: Невозможно закрыть поток, пока не будут записаны все байты.at System.Net.ConnectStream.CloseInternal (Boolean internalCall, Boolean aborting) --- Конец трассировки стека внутренних исключений --- в Amazon.S3.AmazonS3Client.ProcessRequestError (String actionName, запрос HttpWebRequest, исключение WebException, запрос HttpWebResponse errorResponr String, WebHeaderCollection & respHdrs, Тип t) в Amazon.S3.AmazonS3Client.Invoke [T] (S3Request userRequest) в Amazon.S3.AmazonS3Client.PutObject (запрос PutObjectRequest) в BackupToolkit.S3Module.Un StringFileFileName:\ code \ AutoBackupTool \ BackupToolkit \ S3Module.cs: строка 88 в BackupToolkit.S3Module.UploadFiles (String sourceDirectory) в W: \ code \ AutoBackupTool \ BackupToolkit \ S3Module.cs: строка 108

1006* Примечание : 5 МБ - это примерно граница сбоя, она может быть немного ниже или даже выше

Я предполагаю, что время соединения истекло, и поток автоматически закрывается до завершения загрузки файла,

Я пытался найти способ установить длительное время ожидания (но я не могу найти параметр ни в AmazonS3, ни в AmazonS3Config).

Любые идеи о том, как увеличить время ожидания (например, настройки для всего приложения, которые я могу использовать) или оно не связано с проблемой времени ожидания?


Код:

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)) {  }

Ответы [ 5 ]

42 голосов
/ 06 октября 2010

Обновленный ответ:

Я недавно обновил один из моих проектов, использующий Amazon AWS .NET SDK (до версии 1.4.1.0 ), и в этой версии есть два улучшения, которых не было, когда я писал оригинальный ответ здесь .

  1. Теперь вы можете установить Timeout на -1, чтобы иметь неограниченное время для операции put.
  2. Теперь в PutObjectRequest есть дополнительное свойство, называемое ReadWriteTimeout, которое можно установить (в миллисекундах) для тайм-аута на уровне чтения / записи потока, в отличие от всего уровня операции put.

Итак, мой код теперь выглядит так:

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
};
10 голосов
/ 02 апреля 2012

У меня были подобные проблемы с этим, и я начал использовать класс 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);

Когда я набираю это, у меня происходит загрузка 4 ГБ, и она уже прошла дальше, чем когда-либо прежде!

7 голосов
/ 13 июля 2015

AWS SDK для .NET имеет два основных API для работы с Amazon S3. Оба могут загружать большие и маленькие файлы на S3.

1.Низкоуровневый API:

Низкоуровневый API использует тот же шаблон, что и другие низкоуровневые API-интерфейсы служб в SDK. Существует клиентский объект с именем 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: (я бы рекомендовал использовать этот 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);
6 голосов
/ 07 января 2013

Ник Рэнделл получил правильное представление об этом, в дополнение к его сообщению, вот еще один пример с альтернативной обработкой событий и метод получения процента завершения для загруженного файла:

        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];
    }
1 голос
/ 14 сентября 2014

см. Эту тему здесь Как загрузить файл в Amazon 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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...