Question

I have a BlobStream that is created from the method OpenWriter.

var blob = CloudContainer.GetBlobReference(name));
if (blob == null)
{
   return null;
}

return blob.OpenWrite();

Using this stream i would like to seek or set the position, but each time i do this i get a NotSupportedException. After doing some research i found that the canSeek is set to false, which causes this problem. But, the CanSeek is false only if the length is unknown. But the length is known when i run the debugger.

Why is CanSeek false? How can i make it set to true?

Était-ce utile?

La solution 2

You can seek within a page blob - there is explicit support for it in BlobWriteStreamBase class.

I think you could also read & write to specified parts of a Block blob using HTTP Range headers, which would be effectively the same thing as seeking. But I think you'd have to implement that yourself.

Autres conseils

Instead of returning from blobclient.OpenRead, you can return a wrapped stream using below code. Our requirement is to enable parallel and resumable Azure blob downloads from loadbalanced fileservers. There might be some issues in code, please review it and fix them as required.

When returning controller.File(stream, contentType, filename, true) in controller, since last parameter enableRangeProcessing=true, it verifies stream.CanSeek=true and calls stream.Seek with incoming contentrangeheader's range.from value.

So wrap the source with return new SeekableBlobReadStream(blobclient) and send it to controller.

internal class SeekableBlobReadStream : Stream
{
    private Stream stream;
    private readonly BlobBaseClient client;
    private readonly BlobProperties properties;

    public SeekableBlobReadStream(BlobBaseClient client)
    {
        properties = client.GetProperties().Value;
        this.client = client;
    }

    private void PrepareStream(long position = 0)
    {
        if (stream == null || position != 0)
        {
            if (stream != null)
                stream.Dispose();
            stream = client.OpenRead(new BlobOpenReadOptions(false) { Position = position });
        }
    }

    public override bool CanRead => true;

    public override bool CanSeek => true;

    public override bool CanWrite => false;

    public override long Length => properties.ContentLength;

    public override long Position
    {
        get => (stream?.Position).GetValueOrDefault();
        set => PrepareStream(value);
    }

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

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

    public override long Seek(long offset, SeekOrigin origin)
    {
        switch (origin)
        {
            case SeekOrigin.Current:
                offset = Position + offset;
                break;
            case SeekOrigin.End:
                offset = Length - offset;
                break;
        }
        PrepareStream(offset);
        return stream.Position;
    }

    public override void SetLength(long value)
    {
        throw new NotSupportedException();
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        throw new NotSupportedException();
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top