Подтвердить что ты не робот

Как загрузить файлы на Amazon S3 (официальный SDK) размером более 5 МБ (приблизительно)?

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

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

Примечание: 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)) {  }
4b9b3361

Ответ 1

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

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

  • Теперь вы можете установить Timeout на -1, чтобы иметь неограниченное ограничение времени для операции put.
  • В 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
};

Ответ 2

У меня были схожие проблемы, и я начал использовать класс 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 ГБ, и она уже прошла дальше, чем когда-либо раньше!

Ответ 3

AWS SDK для .NET имеет два основных API для работы с Amazon S3.Both могут загружать большие и маленькие файлы на 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. Самый большой польза приходит от размещения объектов. Например, гостиницы определяет, является ли файл большим и переключается в режим многократной загрузки.

Пространство имен: 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);

Ответ 4

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

        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];
    }

Ответ 5

см. эту тему здесь Как загрузить файл в amazon S3 очень просто, используя С#, включая демонстрационный проект для загрузки. это высокий уровень с использованием 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);