Vérifier si un objet blob existe dans le stockage Azure

131

J'ai une question très simple (j'espère!) - Je veux juste savoir si un blob (avec un nom que j'ai défini) existe dans un conteneur particulier. Je le téléchargerai s'il existe, et si ce n'est pas le cas, je ferai autre chose.

J'ai fait quelques recherches sur les tubes intertubes et apparemment, il y avait une fonction appelée DoesExist ou quelque chose de similaire ... mais comme avec tant d'API Azure, cela ne semble plus être là (ou si c'est le cas, a un nom très habilement déguisé).

John
la source
Merci tout le monde. Comme j'utilise StorageClient (et que je préférerais conserver tout mon accès au stockage Azure via cette bibliothèque), j'ai opté pour la méthode FetchAttributes-and-check-for-exceptions suggérée par smarx. Cela `` semble '' un peu bizarre, en ce sens que je n'aime pas avoir des exceptions lancées comme une partie normale de ma logique commerciale - mais j'espère que cela pourra être corrigé dans une future version de StorageClient :)
John

Réponses:

202

La nouvelle API a l'appel de fonction .Exists (). Assurez-vous simplement que vous utilisez le GetBlockBlobReference, qui n'effectue pas l'appel au serveur. Cela rend la fonction aussi simple que:

public static bool BlobExistsOnCloud(CloudBlobClient client, 
    string containerName, string key)
{
     return client.GetContainerReference(containerName)
                  .GetBlockBlobReference(key)
                  .Exists();  
}
Richard
la source
6
Existe-t-il… une… version python?
anpatel
2
Vous vous demandez ce que vous êtes facturé pour vérifier l'existence d'un blob? Cette defo semble être une meilleure façon de procéder que d'essayer de télécharger le blob.
DermFrench
10
@anpatel, version python:len(blob_service.list_blobs(container_name, file_name)) > 0
RaSi
3
vous pouvez mettre à jour votre réponse avec quel paquet nuget doit être installé
batmaci
9
REMARQUE: depuis Microsoft.WindowsAzure.Storage version 8.1.4.0 (.Net Framework v4.6.2), la méthode Exists () n'existe pas en faveur de ExistsAsync () qui est la version qui sera installée pour les projets .NetCore
Adam Hardy
49

Remarque: cette réponse est désormais obsolète. Veuillez consulter la réponse de Richard pour un moyen facile de vérifier l'existence

Non, vous ne manquez pas quelque chose de simple ... nous avons bien caché cette méthode dans la nouvelle bibliothèque StorageClient. :)

Je viens d'écrire un article de blog pour répondre à votre question: http://blog.smarx.com/posts/testing-existence-of-a-windows-azure-blob .

La réponse courte est: utilisez CloudBlob.FetchAttributes (), qui effectue une requête HEAD sur l'objet blob.

user94559
la source
1
FetchAttributes () prend beaucoup de temps à s'exécuter (au moins dans le stockage de développement) si le fichier n'a pas encore été entièrement validé, c'est-à-dire qu'il se compose simplement de blocs non validés.
Tom Robinson
7
Si vous allez quand même récupérer le blob comme le OP a l'intention de le faire, pourquoi ne pas essayer de télécharger le contenu tout de suite? Si ce n'est pas là, il lancera juste comme FetchAttributes. Faire cette vérification en premier n'est qu'une demande supplémentaire, ou est-ce que je manque quelque chose?
Marnix van Valen
Marnix fait un excellent point. Si vous voulez tout de même le télécharger, essayez simplement de le télécharger.
user94559
@Marnix: Si vous appelez quelque chose comme OpenReadça, cela ne lancera ni ne retournera un Stream vide ou quelque chose comme ça. Vous n'obtiendrez des erreurs que lorsque vous commencerez à télécharger à partir de celui-ci. Il est beaucoup plus facile de gérer tout cela en un seul endroit :)
porges
1
@Porges: concevoir une application cloud est une question de «conception pour l'échec». Il y a beaucoup de discussions sur la façon de gérer correctement cette situation. Mais en général, j'irais aussi simplement le télécharger, puis gérer les erreurs Blob manquantes. Non seulement cela, mais si je vérifie l'existence de chaque objet blob, j'augmente le nombre de transactions de stockage, donc ma facture. Vous pouvez toujours avoir un emplacement pour gérer les exceptions / erreurs.
astaykov
16

Semble boiteux que vous devez intercepter une exception pour le tester, le blob existe.

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

Si l'objet blob est public, vous pouvez, bien sûr, simplement envoyer une requête HTTP HEAD - à partir de l'un des zillions de langues / environnements / plates-formes qui savent comment faire cela - et vérifier la réponse.

Les API Azure principales sont des interfaces HTTP basées sur XML REST. La bibliothèque StorageClient est l'un des nombreux wrappers possibles autour d'eux. En voici un autre que Sriram Krishnan a fait en Python:

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

Il montre également comment s'authentifier au niveau HTTP.

J'ai fait une chose similaire pour moi-même en C #, car je préfère voir Azure à travers le prisme de HTTP / REST plutôt que par le prisme de la bibliothèque StorageClient. Pendant un certain temps, je n'avais même pas pris la peine d'implémenter une méthode ExistsBlob. Tous mes blobs étaient publics et il était trivial de faire HTTP HEAD.

Judell
la source
5

La nouvelle bibliothèque de stockage Windows Azure contient déjà la méthode Exist (). Il se trouve dans le fichier Microsoft.WindowsAzure.Storage.dll.

Disponible en tant que package NuGet
Créé par: Microsoft
Id: WindowsAzure.Storage
Version: 2.0.5.1

Voir aussi msdn

huha
la source
2

Si vous n'aimez pas utiliser la méthode d'exception, la version c # de base de ce que Judell suggère est ci-dessous. Méfiez-vous cependant que vous devez vraiment gérer d'autres réponses possibles.

HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create(url);
myReq.Method = "HEAD";
HttpWebResponse myResp = (HttpWebResponse)myReq.GetResponse();
if (myResp.StatusCode == HttpStatusCode.OK)
{
    return true;
}
else
{
    return false;
}
Mad Pierre
la source
4
HttpWebRequest.GetResponse lève une exception s'il y a un 404. Donc je ne vois pas comment votre code contournerait le besoin de gérer les exceptions?
Nitramk
Bon point. Cela me semble nul que GetResponse () jette à ce stade! Je m'attendrais à ce qu'il retourne le 404 car c'est la réponse !!!
Mad Pierre
2

Si votre blob est public et que vous n'avez besoin que de métadonnées:

        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
emert117
la source
1

C'est comme ça que je le fais. Affichage du code complet pour ceux qui en ont besoin.

        // 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.
        }
Apollon
la source
1

Bien que la plupart des réponses ici soient techniquement correctes, la plupart des exemples de code effectuent des appels synchrones / bloquants. Sauf si vous êtes lié par une très ancienne plateforme ou base de code, les appels HTTP doivent toujours être effectués de manière asynchrone, et le SDK le prend entièrement en charge dans ce cas. Utilisez simplement à la ExistsAsync()place de Exists().

bool exists = await client.GetContainerReference(containerName)
    .GetBlockBlobReference(key)
    .ExistsAsync();
Todd Menier
la source
Vous avez raison, l'ancien .Exists () n'est pas la meilleure option. Cependant, alors que l'ancienne API est synchrone, en utilisant await provoque ExistsAsync être aussi synchrone. Donc, je conviens que les appels HTTP devraient généralement être asynchrones. Mais ce code n'est pas ça. Pourtant, +1 pour la nouvelle API!
Richard
2
Merci, mais je ne pourrais pas être plus en désaccord. Exists()est synchrone en ce sens qu'il bloque un thread jusqu'à ce qu'il se termine. await ExistsAscyn()est asynchrone dans la mesure où ce n'est pas le cas. Les deux suivent le même flux logique en ce sens que la ligne de code suivante ne commence pas tant que la précédente n'est pas terminée, mais c'est la nature non bloquante ExistsAsyncqui la rend asynchrone.
Todd Menier
1
Et ... j'ai appris quelque chose de nouveau! :) softwareengineering.stackexchange.com/a/183583/38547
Richard
1

Voici une solution différente si vous n'aimez pas les autres solutions:

J'utilise la version 12.4.1 du package NuGet Azure.Storage.Blobs.

J'obtiens un objet Azure.Pageable qui est une liste de tous les objets blob dans un conteneur. Je vérifie ensuite si le nom du BlobItem est égal à la propriété Name de chaque objet blob à l'intérieur du conteneur utilisant LINQ . (Si tout est valide, bien sûr)

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

Espérons que cela aide quelqu'un à l'avenir.

Zaehos
la source