Überprüfen, ob in Azure Storage ein Blob vorhanden ist

131

Ich habe eine sehr einfache Frage (ich hoffe!) - ich möchte nur herausfinden, ob ein Blob (mit einem von mir definierten Namen) in einem bestimmten Container vorhanden ist. Ich werde es herunterladen, wenn es existiert, und wenn es nicht existiert, werde ich etwas anderes tun.

Ich habe einige Suchen in den Intertubes durchgeführt und anscheinend gab es früher eine Funktion namens DoesExist oder ähnliches ... aber wie bei so vielen Azure-APIs scheint diese nicht mehr vorhanden zu sein (oder wenn ja, hat sie eine sehr geschickt getarnter Name).

John
quelle
Vielen Dank an alle. Da ich StorageClient verwende (und es vorziehen würde, meinen gesamten Azure-Speicherzugriff über diese Bibliothek aufrechtzuerhalten), habe ich die von smarx vorgeschlagene Methode FetchAttributes-and-check-for-exception verwendet. Es fühlt sich ein bisschen anders an, da ich es nicht mag, Ausnahmen als normalen Teil meiner Geschäftslogik auszulösen - aber hoffentlich kann dies in einer zukünftigen StorageClient-Version behoben werden :)
John

Antworten:

202

Die neue API hat den Funktionsaufruf .Exists (). Stellen Sie einfach sicher, dass Sie die verwenden GetBlockBlobReference, die den Aufruf des Servers nicht ausführt. Es macht die Funktion so einfach wie:

public static bool BlobExistsOnCloud(CloudBlobClient client, 
    string containerName, string key)
{
     return client.GetContainerReference(containerName)
                  .GetBlockBlobReference(key)
                  .Exists();  
}
Richard
quelle
6
Gibt es eine Python-Version?
Anpatel
2
Fragen Sie sich, was Ihnen für die Überprüfung der Existenz von Blob berechnet wird? Dieses Defo scheint ein besserer Weg zu sein, als zu versuchen, den Blob herunterzuladen.
DermFrench
10
@anpatel, Python-Version:len(blob_service.list_blobs(container_name, file_name)) > 0
RaSi
3
Sie können Ihre Antwort aktualisieren, mit welcher Nuget-Paket installiert werden soll
Batmaci
9
ANMERKUNG: Ab Microsoft.WindowsAzure.Storage Version 8.1.4.0 (.Net Framework v4.6.2) existiert die Exists () -Methode nicht zugunsten von ExistsAsync (). Diese Version wird für .NetCore-Projekte installiert
Adam Hardy
49

Hinweis: Diese Antwort ist jetzt veraltet. In Richards Antwort finden Sie eine einfache Möglichkeit, die Existenz zu überprüfen

Nein, Sie vermissen nichts Einfaches ... Wir haben diese Methode gut in der neuen StorageClient-Bibliothek versteckt. :) :)

Ich habe gerade einen Blog-Beitrag geschrieben, um Ihre Frage zu beantworten: http://blog.smarx.com/posts/testing-existence-of-a-windows-azure-blob .

Die kurze Antwort lautet: Verwenden Sie CloudBlob.FetchAttributes (), das eine HEAD-Anforderung für den Blob ausführt.

user94559
quelle
1
Die Ausführung von FetchAttributes () dauert lange (zumindest im Entwicklungsspeicher), wenn die Datei noch nicht vollständig festgeschrieben wurde, dh nur aus nicht festgeschriebenen Blöcken besteht.
Tom Robinson
7
Wenn Sie den Blob trotzdem abrufen möchten, wie es das OP beabsichtigt, versuchen Sie doch, den Inhalt sofort herunterzuladen. Wenn es nicht da ist, wird es genau wie FetchAttributes geworfen. Diese Prüfung zuerst durchzuführen ist nur eine zusätzliche Anfrage, oder fehlt mir etwas?
Marnix van Valen
Marnix macht einen ausgezeichneten Punkt. Wenn Sie es trotzdem herunterladen möchten, versuchen Sie einfach, es herunterzuladen.
user94559
@Marnix: Wenn Sie so etwas aufrufen, OpenReadwird kein leerer Stream oder ähnliches geworfen oder zurückgegeben. Sie erhalten nur Fehler, wenn Sie mit dem Herunterladen beginnen. Es ist viel einfacher, dies alles an einem Ort zu erledigen :)
porges
1
@Porges: Beim Entwerfen von Cloud-Anwendungen dreht sich alles um "Design for Failure". Es gibt viele Diskussionen darüber, wie man mit dieser Situation richtig umgeht. Aber im Allgemeinen - ich würde es auch einfach herunterladen und dann die fehlenden Blob-Fehler behandeln. Nicht nur das, aber wenn ich jeden Blob auf Existenz prüfen will, erhöhe ich die Anzahl der Speichertransaktionen, also meine Rechnung. Sie können immer noch einen Ort für die Behandlung von Ausnahmen / Fehlern haben.
Astaykov
16

Scheint lahm, dass Sie eine Ausnahme abfangen müssen, um zu testen, ob der Blob existiert.

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
quelle
9

Wenn der Blob öffentlich ist, können Sie natürlich einfach eine HTTP-HEAD-Anfrage senden - von einer der Millionen Sprachen / Umgebungen / Plattformen, die wissen, wie das geht - und die Antwort überprüfen.

Die wichtigsten Azure-APIs sind RESTful XML-basierte HTTP-Schnittstellen. Die StorageClient-Bibliothek ist einer von vielen möglichen Wrappern um sie herum. Hier ist eine andere, die Sriram Krishnan in Python gemacht hat:

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

Außerdem wird gezeigt, wie Sie sich auf HTTP-Ebene authentifizieren.

Ich habe in C # etwas Ähnliches für mich getan, weil ich Azure lieber durch die Linse von HTTP / REST als durch die Linse der StorageClient-Bibliothek sehe. Eine ganze Weile hatte ich mir nicht einmal die Mühe gemacht, eine ExistsBlob-Methode zu implementieren. Alle meine Blobs waren öffentlich und es war trivial, HTTP HEAD zu machen.

Judell
quelle
5

Die neue Windows Azure-Speicherbibliothek enthält bereits die Exist () -Methode. Es befindet sich in der Microsoft.WindowsAzure.Storage.dll.

Verfügbar als NuGet-Paket
Erstellt von: Microsoft
ID: WindowsAzure.Storage
Version: 2.0.5.1

Siehe auch msdn

huha
quelle
2

Wenn Sie die Ausnahmemethode nicht gerne verwenden, finden Sie unten die grundlegende c # -Version dessen, was Judell vorschlägt. Beachten Sie jedoch, dass Sie auch mit anderen möglichen Antworten umgehen sollten.

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
quelle
4
HttpWebRequest.GetResponse löst eine Ausnahme aus, wenn es eine 404 gibt. Ich sehe also nicht, wie Ihr Code die Notwendigkeit umgehen würde, Ausnahmen zu behandeln?
Nitramk
Gutes Argument. Scheint mir Müll zu sein, den GetResponse () an diesem Punkt wirft! Ich würde erwarten, dass es den 404 zurückgibt, da dies die Antwort ist !!!
Mad Pierre
2

Wenn Ihr Blob öffentlich ist und Sie nur Metadaten benötigen:

        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
quelle
1

So mache ich es. Vollständigen Code für diejenigen anzeigen, die ihn benötigen.

        // 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.
        }
Apollo
quelle
1

Obwohl die meisten Antworten hier technisch korrekt sind, führen die meisten Codebeispiele synchrone / blockierende Aufrufe durch. Wenn Sie nicht an eine sehr alte Plattform oder Codebasis gebunden sind, sollten HTTP-Aufrufe immer asynchron ausgeführt werden, und das SDK unterstützt dies in diesem Fall vollständig. Verwenden Sie einfach ExistsAsync()anstelle von Exists().

bool exists = await client.GetContainerReference(containerName)
    .GetBlockBlobReference(key)
    .ExistsAsync();
Todd Menier
quelle
Sie haben Recht, die alte .Exists () ist nicht die beste Option. Während die alte API synchron ist, führt die Verwendung von await dazu, dass ExistsAsync ebenfalls synchron ist. Daher würde ich zustimmen, dass HTTP-Aufrufe normalerweise asynchron sein sollten. Aber dieser Code ist das nicht. Trotzdem +1 für die neue API!
Richard
2
Danke, aber ich konnte nicht mehr widersprechen. Exists()ist insofern synchron, als es einen Thread blockiert, bis er abgeschlossen ist. await ExistsAscyn()ist insofern asynchron, als dies nicht der Fall ist. Beide folgen dem gleichen logischen Ablauf, da die nächste Codezeile erst beginnt, wenn die vorherige fertig ist, aber es ist die nicht blockierende Natur ExistsAsync, die sie asynchron macht.
Todd Menier
1
Und ... ich habe etwas Neues gelernt! :) softwareengineering.stackexchange.com/a/183583/38547
Richard
1

Hier ist eine andere Lösung, wenn Ihnen die anderen Lösungen nicht gefallen:

Ich verwende Version 12.4.1 des Azure.Storage.Blobs NuGet-Pakets.

Ich erhalte ein Azure.Pageable- Objekt, das eine Liste aller Blobs in einem Container enthält. Ich überprüfe dann mithilfe von LINQ , ob der Name des BlobItem der Name- Eigenschaft jedes Blobs im Container entspricht . (Wenn alles gültig ist, natürlich)

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

Hoffentlich hilft das jemandem in der Zukunft.

Zaehos
quelle