检查Azure存储中是否存在Blob


131

我有一个非常简单的问题(我希望!)-我只想确定特定容器中是否存在斑点(具有我定义的名称)。如果确实存在,我将进行下载,如果不存在,我将进行其他操作。

我已经在Intertube上进行了一些搜索,显然以前曾经有一个称为DidExist的函数或类似的函数...但是与许多Azure API一样,它似乎不再存在(或者如果存在,则具有非常巧妙地变相的名字)。


感谢大家。当我使用StorageClient时(并且希望让我的所有Azure存储访问都通过该库进行),我使用了smarx建议的FetchAttributes-and-check-for-exceptions方法。它确实“感觉”有些不对劲,因为我不希望将异常作为我的业务逻辑的正常部分抛出-但希望可以在以后的StorageClient版本中解决此问题:)
John

Answers:


202

新的API具有.Exists()函数调用。只要确保您使用GetBlockBlobReference,不会执行对服务器的调用即可。它使功能变得简单:

public static bool BlobExistsOnCloud(CloudBlobClient client, 
    string containerName, string key)
{
     return client.GetContainerReference(containerName)
                  .GetBlockBlobReference(key)
                  .Exists();  
}

6
是否有.. python版本?
2014年

2
想知道您是否因为检查Blob而被收取费用?与尝试下载Blob相比,此defo似乎是一种更好的方法。
DermFrench 2014年

10
@ anpatel,Python版本:len(blob_service.list_blobs(container_name, file_name)) > 0
RaSi

3
您可以使用应安装的nuget软件包来更新您的答案
batmaci

9
注意:从Microsoft.WindowsAzure.Storage版本8.1.4.0(.Net Framework v4.6.2)开始,不存在Exists()方法,而偏向于ExistsAsync(),后者是将为.NetCore项目安装的版本
Adam Hardy

49

注意:此答案已过期。请参阅Richard的答案,以一种简单的方法检查是否存在

不,您不会缺少简单的东西……我们很好地将这种方法隐藏在新的StorageClient库中。:)

我刚刚写了一篇博客文章来回答您的问题:http : //blog.smarx.com/posts/testing-existence-of-a-windows-azure-blob

简短的答案是:使用CloudBlob.FetchAttributes(),它对Blob发出HEAD请求。


1
如果文件尚未完全提交(即仅由未提交的块组成),则FetchAttributes()需要很长时间才能运行(至少在开发存储中)。
汤姆·罗宾逊

7
如果您要像OP打算那样以任何方式获取blob,为什么不尝试立即下载内容呢?如果不存在,它将像FetchAttributes一样抛出。首先进行此检查只是一个额外的请求,还是我遗漏了一些东西?
Marnix van Valen 2010年

Marnix提出了一个很好的观点。如果仍要下载,请尝试下载。
user94559 2010年

@Marnix:如果您调用类似的东西OpenRead,则不会抛出或返回空Stream或类似的东西。当您开始从中下载文件时,只会收到错误消息。在一个地方处理所有这些要容易
得多

1
@Porges:设计云应用程序完全是关于“为失败而设计”。有关如何正确处理此情况的讨论很多。但总的来说,我也只是去下载它,然后处理丢失的Blob错误。不仅如此,而且如果我要检查每个Blob是否存在,那么我会增加存储事务的数量,从而增加我的账单。您仍然可以在一个地方处理异常/错误。
astaykov

16

似乎很that脚,您需要捕获一个异常来测试blob是否存在。

public static bool Exists(this CloudBlob blob)
{
    try
    {
        blob.FetchAttributes();
        return true;
    }
    catch (StorageClientException e)
    {
        if (e.ErrorCode == StorageErrorCode.ResourceNotFound)
        {
            return false;
        }
        else
        {
            throw;
        }
    }
}

9

如果Blob是公共的,那么您当然可以发送HTTP HEAD请求-从数十亿种知道如何执行此操作的语言/环境/平台中进行选择,然后检查响应。

核心Azure API是基于RESTful XML的HTTP接口。StorageClient库是围绕它们的许多可能的包装之一。这是Sriram Krishnan在Python中所做的另一件事:

http://www.sriramkrishnan.com/blog/2008/11/python-wrapper-for-windows-azure.html

它还显示了如何在HTTP级别进行身份验证。

我在C#中为自己做了类似的事情,因为我更喜欢通过HTTP / REST而不是通过StorageClient库的视角来查看Azure。相当长一段时间以来,我什至没有费心去实现ExistsBlob方法。我所有的Blob都是公开的,并且执行HTTP HEAD很简单。


5

新的Windows Azure存储库已经包含Exist()方法。它位于Microsoft.WindowsAzure.Storage.dll中。

作为NuGet包提供
创建者:Microsoft
ID:WindowsAzure.Storage
版本:2.0.5.1

另请参见


2

如果您不喜欢使用异常方法,那么judell建议的基本c#版本如下。请注意,尽管您确实也应该处理其他可能的响应。

HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create(url);
myReq.Method = "HEAD";
HttpWebResponse myResp = (HttpWebResponse)myReq.GetResponse();
if (myResp.StatusCode == HttpStatusCode.OK)
{
    return true;
}
else
{
    return false;
}

4
如果存在404,则HttpWebRequest.GetResponse会引发异常。因此,我看不出您的代码将如何规避处理异常的需要?
Nitramk

有道理。在我看来,GetResponse()抛出的垃圾!我希望它返回404,因为这是响应!!!
疯狂皮埃尔

2

如果您的Blob是公开的,并且只需要元数据:

        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
        request.Method = "HEAD";
        string code = "";
        try
        {
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            code = response.StatusCode.ToString();
        }
        catch 
        {
        }

        return code; // if "OK" blob exists


1

这就是我的方法。为需要的人显示完整的代码。

        // Parse the connection string and return a reference to the storage account.
        CloudStorageAccount storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("AzureBlobConnectionString"));

        CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();

        // Retrieve reference to a previously created container.
        CloudBlobContainer container = blobClient.GetContainerReference("ContainerName");

        // Retrieve reference to a blob named "test.csv"
        CloudBlockBlob blockBlob = container.GetBlockBlobReference("test.csv");

        if (blockBlob.Exists())
        {
          //Do your logic here.
        }

1

尽管这里的大多数答案在技术上都是正确的,但是大多数代码示例都在进行同步/阻塞调用。除非您受制于非常老的平台或代码库,否则HTTP调用应始终异步进行,在这种情况下,SDK完全支持它。只需使用ExistsAsync()代替即可Exists()

bool exists = await client.GetContainerReference(containerName)
    .GetBlockBlobReference(key)
    .ExistsAsync();

没错,旧的.Exists()不是最佳选择。但是,虽然旧的API是同步的,但使用await 会使ExistsAsync也同步。因此,我同意HTTP调用通常应该是异步的。但是这段代码不是那样。不过,为新API +1!
理查德

2
谢谢,但我不能不同意。Exists()是同步的,因为它阻塞线程直到完成。await ExistsAscyn()是异步的,因为它不是。两者遵循相同的逻辑流程,因为下一行代码要等到上一行完成后才开始,但这是非阻塞性质,ExistsAsync因此使它异步。
Todd Menier


1

如果您不喜欢其他解决方案,这是一个不同的解决方案:

我正在使用Azure.Storage.Blobs NuGet软件包的12.4.1版本。

我得到一个Azure.Pageable对象,该对象是容器中所有blob的列表。然后,我使用LINQ检查BlobItem名称是否等于容器内每个Blob 的Name属性。(当然,如果一切都有效)

using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using System.Linq;
using System.Text.RegularExpressions;

public class AzureBlobStorage
{
    private BlobServiceClient _blobServiceClient;

    public AzureBlobStorage(string connectionString)
    {
        this.ConnectionString = connectionString;
        _blobServiceClient = new BlobServiceClient(this.ConnectionString);
    }

    public bool IsContainerNameValid(string name)
    {
        return Regex.IsMatch(name, "^[a-z0-9](?!.*--)[a-z0-9-]{1,61}[a-z0-9]$", RegexOptions.Singleline | RegexOptions.CultureInvariant);
    }

    public bool ContainerExists(string name)
    {
        return (IsContainerNameValid(name) ? _blobServiceClient.GetBlobContainerClient(name).Exists() : false);
    }

    public Azure.Pageable<BlobItem> GetBlobs(string containerName, string prefix = null)
    {
        try
        {
            return (ContainerExists(containerName) ? 
                _blobServiceClient.GetBlobContainerClient(containerName).GetBlobs(BlobTraits.All, BlobStates.All, prefix, default(System.Threading.CancellationToken)) 
                : null);
        }
        catch
        {
            throw;
        }
    }

    public bool BlobExists(string containerName, string blobName)
    {
        try
        {
            return (from b in GetBlobs(containerName)
                     where b.Name == blobName
                     select b).FirstOrDefault() != null;
        }
        catch
        {
            throw;
        }
    }
}

希望这对以后的人有所帮助。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.