Работа с потоком ответов Amazon S3 после удаления ответа - PullRequest
7 голосов
/ 02 июня 2011

Я использую Amazon SDK, и у меня есть метод, который возвращает Stream для объекта, хранящегося в сервисе Amazon S3.

Содержит что-то вроде этого:

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

Очевидно, что при этом поток не читается из вызывающего метода, поскольку объект запроса был удален, а когда это сделано, он закрывает поток.

Я не хочу загружать файл в MemoryStream или FileStream.

Если я не использую предложение using, сборщик мусора в какой-то момент удалит объект запроса, поэтому я просто не могу его не использовать.

Я спрашиваю: есть ли способ обернуть или скопировать поток в другой поток, а затем вернуть его без необходимости загрузки файла?

Я использую .NET 3.5.

Редактировать: Метод унаследован от абстрактного класса, а метод вызывающей стороны не знает, что он работает с Amazon. Так что ДОЛЖЕН вернуть поток.

Ответы [ 6 ]

11 голосов
/ 02 июня 2011

Вы не можете работать с потоком после его удаления, но вы можете отложить удаление объекта ответа до тех пор, пока поток ответа не будет использован. Есть три варианта, которые я могу предложить.

  1. Return Response. Один из вариантов - вернуть объект ответа вызывающей стороне. Вызывающий может получить доступ к содержавшемуся потоку ответов, а затем утилизировать ответ по завершении. Это самое простое изменение, но оно требует изменения и для вызывающего абонента.

  2. Обтекание потока. Вместо прямого возврата потока ответа создайте новый объект, который расширяет Stream и оборачивает поток ответа, но также имеет ссылку на сам ответ. Затем, когда ваша оболочка будет удалена, вы сможете внутренне утилизировать объект ответа. Это требует только изменения вашего вызываемого кода, пока возвращаемый тип просто Stream.

  3. Обратный вызов. Не возвращайте ничего из метода и используйте вместо него механизм обратного вызова. Примите Action<Stream> в качестве параметра и вызовите этот обратный вызов с потоком. Таким образом вызывается код вызывающего абонента, и вы по-прежнему можете распоряжаться ответом и потоком. Это самый безопасный механизм, поскольку вы не полагаетесь на то, что вызывающий абонент может что-либо распоряжаться, но требует большинства изменений.

3 голосов
/ 26 октября 2015

В классе TransferUtility есть метод OpenStream, который возвращает объект потока.

публичный поток OpenStream ( Строка bucketName, Строковый ключ )

Я просмотрел исходный код AWSSDK и обнаружил, что в SDK OpenStream просто возвращает поток ответов напрямую. (Он не использует выражение «using» для объекта ответа.)

1 голос
/ 06 декабря 2011

Была такая же проблема (подумал я). Но вы пытались не использовать «использование». Это не будет использовать поток и отправлять его вызывающей стороне, которая будет нести ответственность за его удаление. Так просто.

    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;
1 голос
/ 02 июня 2011

Если ваша функция возвращает объект response (без использования оператора using), и вызывающая сторона назначает его переменной, все равно будет ссылка на объект response. Таким образом, мусор не будет подходящим.

0 голосов
/ 09 июня 2017

Чтобы добавить пример кода в ответ @Jun Y. Это то, что я сделал, и это было самое чистое решение на сегодняшний день.

using (var client = new AmazonS3Client(Amazon.RegionEndpoint.USEast2))
{
    var transferUtility = new TransferUtility(client);
    return await transferUtility.OpenStreamAsync(S3BucketName, key);
}
0 голосов
/ 05 марта 2015

Для полноты, и поскольку я перешел к варианту @Samuel № 2 (Wrap the stream), который, как прокомментировал @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);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...