Перевірка наявності блобу в Azure Storage


131

У мене дуже просте запитання (я сподіваюся!) - я просто хочу з’ясувати, чи є певний крап (з ім’ям, яке я визначив) у певному контейнері. Я завантажую його, якщо він існує, а якщо цього не стане, я зроблю щось інше.

Я кілька пошукав по інтертубах, і, мабуть, раніше була функція під назвою DoesExist або щось подібне ... але, як і у багатьох API-програм Azure, цього більше не існує (або, якщо він є, має дуже спритно замасковане ім’я).


Дякую всім. Оскільки я використовую StorageClient (і вважаю за краще тримати весь доступ до Azure Storage через цю бібліотеку), я пішов із методом FetchAttributes-and-check-for -ptions, який пропонував smarx. Це "відчуває себе трохи", тому що мені не подобається, що винятки кидаються як нормальна частина моєї бізнес-логіки - але, сподіваємось, це можна зафіксувати у майбутній версії StorageClient :)
Джон

Відповіді:


202

Новий API має виклик функції .Exists (). Просто переконайтеся, що ви використовуєте те GetBlockBlobReference, що не виконує дзвінок на сервер. Це робить функцію такою простою, як:

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

6
Чи є .. ... версія пітона?
anpatel

2
Цікаво, що вам платять за перевірку краплі? Це дефо здається кращим способом, ніж спроба завантажити блоб.
DermFrench

10
@anpatel, версія пітона:len(blob_service.list_blobs(container_name, file_name)) > 0
RaSi

3
ви можете оновити свою відповідь, яким пакунком нугетів слід встановити
batmaci

9
ПРИМІТКА: Станом на версію Microsoft.WindowsAzure.Storage 8.1.4.0 (.Net Framework v4.6.2) метод Exists () не існує на користь ExistsAsync (), яка версія, яка буде встановлена ​​для проектів .NetCore
Адам Харді

49

Примітка. Ця відповідь застаріла. Будь ласка, дивіться відповідь Річарда про простий спосіб перевірити наявність

Ні, ви не пропускаєте чогось простого ... ми зробили хорошу роботу, сховавши цей метод у новій бібліотеці StorageClient. :)

Я щойно написав повідомлення в блозі, щоб відповісти на ваше запитання: http://blog.smarx.com/posts/testing-existence-of-a-windows-azure-blob .

Коротка відповідь: використовуйте CloudBlob.FetchAttributes (), який робить запит HEAD проти блобу.


1
FetchAttributes () займає тривалий час (хоча б у сховищі розробок), якщо файл ще не був повністю зафіксований, тобто просто складається з непосланих блоків.
Том Робінсон,

7
Якщо ви все одно отримаєте крапку, як це має зробити ОП, чому б не спробувати і завантажити вміст відразу? Якщо його немає, він кине так само, як FetchAttributes. Робити цю перевірку спочатку - це лише додатковий запит, чи я щось пропускаю?
Marnix van Valen

Marnix робить відмінний момент. Якщо ви все-таки завантажуєте його, просто спробуйте його завантажити.
user94559

@Marnix: Якщо ви зателефонуєте на щось подібне, OpenReadвоно не кине або поверне порожній потік або щось подібне. Помилки ви отримаєте лише тоді, коли почнете завантажувати з нього. Набагато простіше впоратися з усім цим в одному місці :)
porges

1
@Porges: проектування хмарного додатка - це все, що стосується "дизайну для відмови". Існує багато дискусій, як правильно впоратися з цією ситуацією. Але загалом - я б також просто зайшов і завантажував його, а потім обробляв відсутні помилки Blob. Мало того, але якщо я збираюся перевіряти наявність кожної краплі, я збільшую кількість транзакцій зберігання, таким чином мій рахунок. Ви все ще можете мати одне місце для обробки винятків / помилок.
астайков

16

Здається, кульга, що вам потрібно вилучити виняток, щоб перевірити його, чи існує крапля.

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

Якщо блоб є загальнодоступним, ви, звичайно, можете просто надіслати запит HTTP HEAD - з будь-якого з мільйонів мов / середовищ / платформ, які знають, як це зробити - і перевірити відповідь.

Основні API Azure - це HTTP-інтерфейси на основі RESTful XML. Бібліотека StorageClient - одна з багатьох можливих обгортків навколо них. Ось ще одне, що зробив Срірам Крішнан в Python:

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

Він також показує, як здійснити автентифікацію на рівні HTTP.

Я робив подібну річ для себе в C #, тому що я вважаю за краще бачити Azure через об'єктив HTTP / REST, а не через об'єктив бібліотеки StorageClient. Довгий час я навіть не намагався впровадити метод ExistsBlob. Усі мої краплини були публічними, і робити HTTP HEAD було тривіально.


5

Нова бібліотека зберігання Windows Azure вже містить метод Exist (). Це в Microsoft.WindowsAzure.Storage.dll.

Доступний як пакунок NuGet
Створено: Microsoft
Id: WindowsAzure.Storage
Версія: 2.0.5.1

Див. Також msdn


2

Якщо вам не подобається використовувати метод виключень, то нижче наведена основна версія # c, що пропонує judell. Але будьте обережні, що вам теж слід поводитися з іншими можливими відповідями.

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
HttpWebRequest.GetResponse викидає виняток, якщо є 404. Тож я не бачу, як ваш код обходив би необхідність обробляти винятки?
Nitramk

Справедливий пункт. Мені здається сміття, яке GetResponse () кидає в цей момент! Я б очікував, що він поверне 404, як це відповідь !!!
Божевільний П'єр

2

Якщо ваш блоб публічний і вам потрібні лише метадані:

        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 синхронізований, використання очікування викликає також, що ExistsAsync також буде синхронним. Отже, я погоджуюся, що дзвінки HTTP зазвичай мають бути асинхронними. Але цей код - це не те. Все-таки +1 для нового API!
Річард

2
Дякую, але я більше не могла погодитися. Exists()є синхронним тим, що блокує нитку до її завершення. await ExistsAscyn()асинхронний тим, що цього не робить. Обидва дотримуються одного і того ж логічного потоку в тому, що наступний рядок коду не починається, поки не буде виконаний попередній, але його неблокуюча природа ExistsAsyncробить його асинхронним.
Тодд Меньє

1
І ... я дізнався щось нове! :) softwareengineering.stackexchange.com/a/183583/38547
Річард

1

Ось інше рішення, якщо вам не подобаються інші рішення:

Я використовую версію 12.4.1 пакету Azure.Storage.Blobs NuGet.

Я отримую об'єкт Azure.Pageable, який є списком всіх крапок в контейнері. Потім я перевіряю, чи ім'я BlobItem дорівнює властивості Name кожної крапки всередині контейнера, що використовує LINQ . (Якщо все дійсно, звичайно)

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

Сподіваємось, це допоможе комусь у майбутньому.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.