在Azure存储中检查blob是否存在

158

我有一个非常简单的问题(希望如此!)- 我想找出是否在特定容器中存在一个由我定义名称的 blob。 如果它存在,我将下载它,如果不存在,我将执行其他操作。

我在互联网上进行了一些搜索,显然曾经有一个名为 DoesExist 或类似名称的函数...但是就像许多 Azure API 一样,它似乎已经消失了(或者如果存在,那它有一个非常巧妙的伪装名称)。


1
谢谢大家。由于我正在使用StorageClient(并且希望所有的Azure存储访问都通过该库进行),所以我选择了smarx建议的FetchAttributes-and-check-for-exceptions方法。这种方法在某种程度上感觉有些不对,因为我不喜欢将异常作为业务逻辑的正常部分抛出 - 但希望这可以在未来的StorageClient版本中得到修复 :) - John
13个回答

231
新的API有.Exists()函数调用。只需确保使用GetBlockBlobReference,该函数不会执行到服务器的调用。这使得函数变得非常简单:
public static bool BlobExistsOnCloud(CloudBlobClient client, 
    string containerName, string key)
{
     return client.GetContainerReference(containerName)
                  .GetBlockBlobReference(key)
                  .Exists();  
}

12
有没有Python版本? - anpatel
4
想知道检查 Blob 是否存在会被收取多少费用?这绝对似乎是比尝试下载该 Blob 更好的方法。 - DermFrench
14
在Python中,@anpatel的代码表示检查名为"container_name"的储存容器中是否存在名为"file_name"的文件。具体而言,它调用了一个名为"list_blobs"的函数来列出特定容器中的所有Blob(二进制大型对象),然后通过判断列表的长度是否大于0来确定文件是否存在。 - RaSi
4
你可以更新你的回答,告诉我们应该安装哪个NuGet软件包。 - Emil
15
自Microsoft.WindowsAzure.Storage版本8.1.4.0 (.Net Framework v4.6.2)起,Exists()方法已被ExistsAsync()代替。对于.NetCore项目,将安装ExistsAsync()版本。 - Adam Hardy
显示剩余7条评论

52
注意:此答案已过时,请参见Richard的答案以获得一种轻松的检查存在方式 不,你没有错过什么简单的方法...我们在新的StorageClient库中很好地隐藏了这个方法。 :)
我刚写了一篇博客来回答你的问题:http://blog.smarx.com/posts/testing-existence-of-a-windows-azure-blob
简短回答是:使用CloudBlob.FetchAttributes()方法,它会对blob执行HEAD请求。

1
如果文件尚未完全提交,即仅由未提交的块组成,则FetchAttributes()在运行时(至少在开发存储中)需要很长时间。 - Tom Robinson
7
如果您打算像原帖中的意图一样获取 Blob,为什么不尝试立即下载内容呢?如果 Blob 不存在,它会像 FetchAttributes 一样抛出异常。首先进行此检查只是额外的请求,还是我漏掉了什么? - Marnix van Valen
Marnix提出了一个很好的观点。如果你无论如何都要下载它,那就试着去下载吧。 - user94559
@Marnix:如果你调用类似OpenRead的函数,它不会抛出异常或返回空流等任何内容。只有当你开始从中下载时才会出现错误。将所有这些处理放在一个地方要容易得多 :) - porges
1
@Porges:设计云应用程序是关于“面向失败设计”的。有很多讨论如何适当地处理这种情况。但总的来说 - 我也只会去下载它,然后处理丢失的 Blob 错误。不仅如此,如果我要检查每个 Blob 的存在,我将增加存储事务的数量,从而增加我的账单。您仍然可以有一个处理异常/错误的统一位置。 - astaykov

17

似乎很糟糕,需要捕获异常来测试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;
        }
    }
}

10
如果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的视角看Azure,而不是通过StorageClient库的视角。相当长一段时间,我甚至都没有实现ExistsBlob方法。我的所有blob都是公开的,使用HTTP HEAD也很简单。

8

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

我使用的是Azure.Storage.Blobs NuGet包的12.4.1版本。

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

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

希望这能帮助未来的某个人。


6
新的Windows Azure存储库已经包含Exist()方法,它在Microsoft.WindowsAzure.Storage.dll中。作为NuGet包可用。
创建者:Microsoft
ID:WindowsAzure.Storage
版本:2.0.5.1
此外,请参阅MSDN

4
这是我处理的方式。对于那些需要它的人,我展示完整的代码。
        // 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.
        }

3

3
如果您的 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

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

5
如果出现404错误,HttpWebRequest.GetResponse会抛出异常。因此,我不明白你的代码如何规避处理异常的需要? - Nitramk
1
说得好。在那个点上,GetResponse()抛出异常对我来说似乎很糟糕!我期望它返回404作为响应!!! - Mad Pierre

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接