在处理响应后使用Amazon S3响应流

时间:2011-06-02 11:19:58

标签: c# asp.net stream amazon-s3

我正在使用亚马逊SDK,我有一个方法可以为存储在Amazon S3服务中的对象返回一个流。

它包含以下内容:

var request = new GetObjectRequest().WithBucketName(bucketName).WithKey(keyName);
using (var response = client.GetObject(request))
{
    return response.ResponseStream;
}

显然,执行此操作时,流不能从调用方法中读取,因为请求对象已被处理,完成后会关闭流。

我不想将文件下载到MemoryStream或FileStream。

如果我不使用using子句,垃圾收集器会在某个时候处理请求对象,所以我不能不使用它。

我要问的是,有没有办法将Stream包装或复制到另一个Stream中然后返回它而不必下载文件?

我正在使用.NET 3.5。

编辑:该方法继承自抽象类,调用方法不知道它与Amazon一起使用。所以它需要返回一个Stream。

6 个答案:

答案 0 :(得分:11)

在处理完流后,您无法使用该流,但您可以推迟处理响应对象,直到使用了响应流。我可以提出三种选择。

  1. 返回响应。一个选项是将响应对象返回给调用者。调用者可以访问包含的响应流,然后在完成后处理响应。这是最简单的更改,但也需要调用者进行更改。

  2. 包裹流。不是直接返回响应流,而是创建一个新对象,该对象扩展Stream并包装响应流,但也有一个对响应本身的引用。然后,当您的包装器被丢弃时,您可以在内部处置响应对象。只要返回的类型只是Stream,这只需要更改被调用的代码。

  3. 回调。不要从方法中返回任何内容,而是使用回调机制。接受Action<Stream>作为参数,并使用流调用此回调。这样调用了调用者代码,您仍然可以控制处理响应和流。这是最安全的机制,因为您不依赖于调用者处理任何内容,但需要进行大部分更改。

答案 1 :(得分:3)

TransferUtility类中有一个方法OpenStream,它返回一个流对象。

public Stream OpenStream(          String bucketName,          字符串键 )

我浏览了AWSSDK的源代码,在SDK中发现OpenStream只是直接返回响应流。 (它没有使用&#34;在响应对象上使用&#34;语句。)

答案 2 :(得分:1)

如果函数返回response对象(不使用using语句),并且调用者将其分配给变量,则仍会有对response对象的引用。因此,它不会被合格的垃圾收集。

答案 3 :(得分:1)

有同样的问题(我想)。但你有没有试过不使用“使用”。这不会使用流并将其发送给有责任处理它的调用者。就这么简单。

    var request = new GetObjectRequest { BucketName = containerName, Key = blobName };
    GetObjectResponse response = null;

        try
        {
            response = client.GetObject(request));
        }
        catch (AmazonS3Exception ex)
        {
            if ((ex.ErrorCode == "NoSuchBucket") || (ex.ErrorCode == "AccessDenied") || (ex.ErrorCode == "InvalidBucketName") || (ex.ErrorCode == "NoSuchKey"))
            {
                return null;
            }

            throw;
        }

        return response.ResponseStream;

答案 4 :(得分:0)

为了完整性,自从我使用@Samuel选项2(包裹流)@spakinz评论他也做了,我在这里包括我所谓的AmazonS3Stream的实现

public class AmazonS3Stream : Stream
{
    private Stream stream;
    private GetObjectResponse response;

    public AmazonS3Stream(GetObjectResponse response)
    {
        this.stream = response.ResponseStream;
        this.response = response;
    }

    // The whole purpose of this class
    protected override void Dispose(bool disposing)
    {
        // base.Dispose(disposing); // Do we really need this line? Probably not since I tested it and I can see that the stream is disposed when Response.Dispose is called by itself. And that makes sense because we know that this.stream is pointing to response.ResponseStream (that's what we declared in the constructor: this.stream = response.ResponseStream; ) So, what do we expect from response.Dispose() ? Obviously the first thing it would do is call ResponseStream.Dispose()
        response.Dispose();
    }

    public override long Position
    {
        get { return stream.Position; }
        set { stream.Position = Position; }
    }

    public override long Length
    {
        get { return stream.Length; }
    }

    public override bool CanRead
    {
        get { return stream.CanRead; }
    }

    public override bool CanSeek
    {
        get { return stream.CanSeek; }
    }

    public override bool CanWrite
    {
        get { return stream.CanWrite; }
    }

    public override void Flush()
    {
        stream.Flush();
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        stream.Write(buffer, offset, count);
    }

    public override void SetLength(long value)
    {
        stream.SetLength(value);
    }

    public override long Seek(long offset, SeekOrigin origin)
    {
        return stream.Seek(offset, origin);
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        return stream.Read(buffer, offset, count);
    }
}

答案 5 :(得分:0)

将代码示例添加到@Jun Y。的答案中。这就是我所做的,这是迄今为止最干净的解决方案。

using (var client = new AmazonS3Client(Amazon.RegionEndpoint.USEast2))
{
    var transferUtility = new TransferUtility(client);
    return await transferUtility.OpenStreamAsync(S3BucketName, key);
}