【问题标题】:How to enable seeking in Azure Blob stream如何在 Azure Blob 流中启用搜索
【发布时间】:2013-05-11 12:46:56
【问题描述】:

我有一个从 OpenWriter 方法创建的 BlobStream。

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

return blob.OpenWrite();

使用这个流我想寻找或设置位置,但每次我这样做我都会得到一个 NotSupportedException。在做了一些研究后,我发现 canSeek 设置为 false,这导致了这个问题。但是,仅当长度未知时,CanSeek 才为假。但是当我运行调试器时长度是已知的。

为什么 CanSeek 是假的? 如何将其设置为 true?

【问题讨论】:

  • 您使用的是什么版本的客户端库?底层 blob(块或页)是什么类型?在最新的 v2.0 客户端中,您似乎只能在 Page blob 上查找写入流,所以这可能是不可能的。
  • 我正在使用块 blob。
  • 块和页面有什么大的区别吗?
  • 我已经快速切换到 page 看看它是否有效。我会及时通知你。
  • 我对页面 blob 的工作并不多,但显然您可以写入页面 blob,否则您将如何创建一个? BlobWriteStreamBase 类明确支持写入和查找页 blob。如果您说明您使用的是哪个客户端库版本,并发布了您用于创建 blob 的代码,将会很有帮助。

标签: c# azure azure-blob-storage streamwriter seek


【解决方案1】:

您可以使用以下代码返回包装流,而不是从 blobclient.OpenRead 返回。我们的要求是从负载平衡的文件服务器启用并行和可恢复的 Azure blob 下载。代码中可能存在一些问题,请检查并根据需要进行修复。

当在控制器中返回controller.File(stream, contentType, filename, true) 时,从上一个参数enableRangeProcessing=true 开始,它会验证stream.CanSeek=true 并使用传入的contentrangeheader 的range.from 值调用stream.Seek

所以用return new SeekableBlobReadStream(blobclient) 包装源并将其发送到控制器。

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();
    }
}

【讨论】:

  • 这是一个很好的解决方案,谢谢分享。
【解决方案2】:

您可以在页面 blob 中查找 - 在 BlobWriteStreamBase 类中有明确的支持。

我认为您还可以使用 HTTP Range 标头读取和写入块 blob 的指定部分,这实际上与查找相同。但我认为你必须自己实施。

【讨论】:

  • 使用 page blob 搜索存在限制。如果我错了,请纠正我,但我认为你一次只能读写 512 个字节。这意味着必须对每个位置增量 512 进行搜索。(512*x,其中 x 为整数)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-06
  • 2018-03-10
  • 2019-10-09
  • 1970-01-01
  • 2020-01-02
  • 2016-08-14
相关资源
最近更新 更多