How can I get the bytes of a GetObjectResponse from S3?

21,533

Solution 1

Here's the solution I found for anyone else who needs it:

GetObjectResponse response = client.GetObject(request);
using (Stream responseStream = response.ResponseStream)
{
    var bytes = ReadStream(responseStream);
    var download = new FileContentResult(bytes, "application/pdf");
    download.FileDownloadName = filename;
    return download;
}

public static byte[] ReadStream(Stream responseStream)
{
    byte[] buffer = new byte[16 * 1024];
    using (MemoryStream ms = new MemoryStream())
    {
        int read;
        while ((read = responseStream.Read(buffer, 0, buffer.Length)) > 0)
        {
            ms.Write(buffer, 0, read);
        }
        return ms.ToArray();
    }
}

Solution 2

Just another option:

Stream rs;    
using (IAmazonS3 client = Amazon.AWSClientFactory.CreateAmazonS3Client())
{
    GetObjectRequest getObjectRequest = new GetObjectRequest();
    getObjectRequest.BucketName = "mybucketname";
    getObjectRequest.Key = "mykey";

    using (var getObjectResponse = client.GetObject(getObjectRequest))
    {
              getObjectResponse.ResponseStream.CopyTo(rs);
    }
}    

Solution 3

Stream now has asynchronous methods. In C# 8, you can do this:

public async Task<byte[]> GetAttachmentAsync(string objectPointer)
{
    var objReq = new GetObjectRequest
    {
        BucketName = "bucket-name",
        Key = objectPointer,    // the file name
    };

    using var objResp = await _s3Client.GetObjectAsync(objReq);
    using var ms = new MemoryStream();
    await objResp.ResponseStream.CopyToAsync(ms, _ct);  // _ct is a CancellationToken
    return ms.ToArray();
}

This won't block any threads while the IO occurs.

Solution 4

I struggled to get the cleaner method offered by Alex to work (not sure what I'm missing), but I wanted to do it w/o the extra ReadStream method offered by Erica (although it worked)... here is what I wound up doing:

var s3Client = new AmazonS3Client(AccessKeyId, SecretKey, Amazon.RegionEndpoint.USEast1);
    using (s3Client)
    {
        MemoryStream ms = new MemoryStream();
        GetObjectRequest getObjectRequest = new GetObjectRequest();
        getObjectRequest.BucketName = BucketName;
        getObjectRequest.Key = awsFileKey;

        using (var getObjectResponse = s3Client.GetObject(getObjectRequest))
        {
            getObjectResponse.ResponseStream.CopyTo(ms);
        }
        var download = new FileContentResult(ms.ToArray(), "image/png"); //"application/pdf"
        download.FileDownloadName = ToFilePath;
        return download;
    }
Share:
21,533

Related videos on Youtube

Erica Stockwell-Alpert
Author by

Erica Stockwell-Alpert

merge delete

Updated on May 31, 2020

Comments

  • Erica Stockwell-Alpert
    Erica Stockwell-Alpert almost 4 years

    I'm retrieving a file from Amazon S3. I want to convert the file to bytes so that I can download it as follows:

    var download = new FileContentResult(bytes, "application/pdf");
    download.FileDownloadName = filename;
    return download;
    

    I have the file here:

    var client = Amazon.AWSClientFactory.CreateAmazonS3Client(
            accessKey,
            secretKey,
            config
            );
    GetObjectRequest request = new GetObjectRequest();
    GetObjectResponse response = client.GetObject(request);          
    

    I know about response.WriteResponseStreamToFile() but I want to download the file to the regular downloads folder. If I convert the GetObjectResponse to bytes, I can return the file. How can I do this?

  • Ricardo stands with Ukraine
    Ricardo stands with Ukraine over 7 years
    The 'ResponseStream.CopyTo' is cleaner than to have to create method 'ReadStream(Stream responseStream)' as in other answer. Also you can use 'CopyToAsync' and make method async.
  • sina_Islam
    sina_Islam about 4 years
    I am little confused about how it will behave when I will call it from the synchronous method.