Проверка наличия большого двоичного объекта в хранилище Azure

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

Я провел несколько поисков по интертубам, и, по-видимому, раньше была функция под названием DoesExist или что-то подобное ... но, как и в случае со многими API-интерфейсами Azure, этого больше нет (или, если есть, есть очень хитро замаскированное имя).


person John    schedule 15.04.2010    source источник
comment
Спасибо всем. Поскольку я использую StorageClient (и предпочел бы, чтобы весь мой доступ к хранилищу Azure проходил через эту библиотеку), я выбрал метод FetchAttributes-and-check-for-exceptions, который предложил smarx. Это немного не так, потому что мне не нравится, когда исключения выбрасываются как обычная часть моей бизнес-логики, но, надеюсь, это можно исправить в будущей версии StorageClient :)   -  person John    schedule 18.04.2010


Ответы (13)


В новом API есть вызов функции .Exists (). Просто убедитесь, что вы используете GetBlockBlobReference, который не выполняет вызов сервера. Это делает функцию такой же простой, как:

public static bool BlobExistsOnCloud(CloudBlobClient client, 
    string containerName, string key)
{
     return client.GetContainerReference(containerName)
                  .GetBlockBlobReference(key)
                  .Exists();  
}
person Richard    schedule 10.05.2013
comment
Есть .. версия на питоне? - person anpatel; 24.04.2014
comment
@MyName Ну, я не предпочитаю python, поэтому я с ним не знаком. Однако если посмотреть на SDK с открытым исходным кодом для Python похоже, что вы могли бы использовать функцию list_blobs и присвоить ей префикс, который представляет собой полное имя файла. Конечно, вам придется защитить себя от таких случаев, как File1 и File11 (где имя большого двоичного объекта является префиксом другого большого двоичного объекта). Но это вариант, который я считаю доступным. - person Richard; 24.04.2014
comment
@Richard Ах, интересно, спасибо за предложение, я попробую, когда появится следующая возможность. На самом деле я закончил тем, что попробовал {} catch {} в python (try: except: pass), что, как мне кажется, все еще неправильно :( - person anpatel; 24.04.2014
comment
Интересно, сколько вам нужно заплатить за проверку существования BLOB-объекта? Этот defo кажется лучшим способом, чем попытка загрузить blob. - person DermFrench; 23.09.2014
comment
@anpatel, версия Python: len(blob_service.list_blobs(container_name, file_name)) > 0 - person RaSi; 06.04.2015
comment
Если он не обращается к серверу, как он узнает наверняка, что этот BLOB-объект существует / нет? - person stack247; 29.05.2015
comment
.Exists () вызывает сервер. GetBlockBlobReference () - нет. - person Richard; 29.05.2015
comment
вы можете обновить свой ответ, указав, какой пакет nuget должен быть установлен - person Emil; 18.10.2016
comment
ПРИМЕЧАНИЕ. Начиная с Microsoft.WindowsAzure.Storage версии 8.1.4.0 (.Net Framework v4.6.2) метод Exists () не существует в пользу ExistsAsync (). Это версия, которая будет установлена ​​для проектов .NetCore. - person Adam Hardy; 23.11.2017
comment
Что здесь происходит, если контейнера не существует? - person ajbeaven; 01.09.2020
comment
Привет, спасибо за ваш ответ, но просто хочу, есть ли версия javascript вышеупомянутой проверки или нет - person Mr Perfect; 21.09.2020

Примечание. Этот ответ уже устарел. См. Ответ Ричарда, чтобы узнать, как это легко проверить.

Нет, вы не упускаете чего-то простого ... мы хорошо поработали, скрывая этот метод в новой библиотеке StorageClient. :)

Я только что написал сообщение в блоге, чтобы ответить на ваш вопрос: http://blog.smarx.com/posts/testing-existence-of-a-windows-azure-blob.

Короткий ответ: используйте CloudBlob.FetchAttributes (), который выполняет запрос HEAD для большого двоичного объекта.

person user94559    schedule 16.04.2010
comment
FetchAttributes () требует много времени для запуска (по крайней мере, в хранилище разработки), если файл еще не был полностью зафиксирован, т.е. просто состоит из незафиксированных блоков. - person Tom Robinson; 23.08.2010
comment
Если вы все равно собираетесь получить BLOB-объект, как намеревается сделать OP, почему бы не попробовать загрузить контент прямо сейчас? Если его там нет, он будет сгенерирован так же, как FetchAttributes. Выполнение этой проверки в первую очередь - это всего лишь дополнительный запрос, или я что-то упустил? - person Marnix van Valen; 27.08.2010
comment
Марникс делает отличное заявление. Если вы все равно собираетесь его скачать, просто попробуйте скачать. - person user94559; 27.08.2010
comment
@Marnix: если вы вызовете что-то вроде OpenRead, он не будет генерировать или возвращать пустой поток или что-то в этом роде. Вы получите ошибки только тогда, когда начнете скачивать с него. Разобраться со всем этим в одном месте намного проще :) - person porges; 08.12.2010
comment
@Porges: разработка облачного приложения - это все о дизайне на случай отказа. Сейчас ведется много дискуссий о том, как правильно справиться с этой ситуацией. Но в целом - я бы просто пошел и загрузил его, а затем обработал недостающие ошибки Blob. Не только это, но и если я собираюсь проверять наличие каждого большого двоичного объекта, я увеличиваю количество транзакций хранилища, следовательно, мой счет. У вас все еще может быть одно место для обработки исключений / ошибок. - person astaykov; 18.11.2011

Кажется хромым, что вам нужно поймать исключение, чтобы проверить, существует ли 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;
        }
    }
}
person nathanw    schedule 04.05.2010

Если большой двоичный объект является общедоступным, вы, конечно, можете просто отправить 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 было тривиально.

person judell    schedule 17.04.2010

Новая библиотека хранилища Windows Azure уже содержит метод Exist (). Он находится в Microsoft.WindowsAzure.Storage.dll.

Доступен как пакет NuGet
Создано: Microsoft
Идентификатор: WindowsAzure.Storage
Версия: 2.0.5.1

См. также msdn

person huha    schedule 03.05.2013

Если вам не нравится использовать метод исключения, то базовая версия 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;
}
person Mad Pierre    schedule 18.11.2011
comment
HttpWebRequest.GetResponse выдает исключение, если есть 404. Поэтому я не понимаю, как ваш код может обойти необходимость обработки исключений? - person Nitramk; 08.12.2011
comment
Честная оценка. Мне кажется чушь то, что GetResponse () выбрасывает в этот момент! Я ожидал, что он вернет 404, так как это ответ !!! - person Mad Pierre; 14.12.2011

Если ваш большой двоичный объект является общедоступным и вам нужны только метаданные:

        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
person emert117    schedule 31.12.2018

Вот другое решение, если вам не нравятся другие решения:

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

Я получаю объект Azure.Pageable, который представляет собой список всех больших двоичных объектов в контейнере. Затем я проверяю, совпадает ли имя BlobItem со свойством Name каждого большого двоичного объекта внутри контейнера, использующего < strong> 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;
        }
    }
}

Надеюсь, это поможет кому-то в будущем.

person Zaehos    schedule 07.04.2020

С обновленным SDK, как только у вас будет CloudBlobReference, вы можете вызвать Exists () для своей ссылки.

См. http://msdn.microsoft.com/en-us/library/microsoft.windowsazure.storage.blob.cloudblockblob.exists.aspx

person Babak Naffas    schedule 05.08.2013

Я так и делаю. Показан полный код для тех, кому он нужен.

        // 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.
        }
person Apollo    schedule 26.02.2018

Хотя большинство ответов здесь технически верны, большинство примеров кода совершают синхронные / блокирующие вызовы. Если вы не связаны очень старой платформой или базой кода, HTTP-вызовы должны всегда выполняться асинхронно, и SDK полностью поддерживает это в этом случае. Просто используйте ExistsAsync() вместо Exists().

bool exists = await client.GetContainerReference(containerName)
    .GetBlockBlobReference(key)
    .ExistsAsync();
person Todd Menier    schedule 17.10.2018
comment
Вы правы, старый .Exists () - не лучший вариант. Однако, хотя старый API является синхронным, использование await заставляет ExistsAsync также быть синхронным. Итак, я согласен с тем, что HTTP-вызовы должны обычно быть асинхронными. Но этот код не тот. Тем не менее, +1 за новый API! - person Richard; 30.04.2019
comment
Спасибо, но больше не могу не согласиться. Exists() является синхронным в том смысле, что он блокирует поток до его завершения. await ExistsAscyn() асинхронен в том смысле, что это не так. Оба следуют одному и тому же логическому потоку: следующая строка кода не начинается до тех пор, пока не будет завершена предыдущая, но неблокирующая природа ExistsAsync делает ее асинхронной. - person Todd Menier; 30.04.2019
comment
И ... я узнал кое-что новое! :) softwareengineering.stackexchange.com/a/183583/38547 - person Richard; 02.05.2019

С библиотекой хранилища BLOB-объектов Azure v12 вы можете использовать BlobBaseClient.Exists()/BlobBaseClient.ExistsAsync()

Ответил на другой аналогичный вопрос: https://stackoverflow.com/a/63293998/4865541

person Jaliya Udagedara    schedule 07.08.2020

Версия Java для того же (с использованием нового SDK v12)

При этом используется авторизация учетных данных общего ключа, которая является ключом доступа к учетной записи.

    StorageSharedKeyCredential credential = new StorageSharedKeyCredential(accountName, accountKey);
    String endpoint = String.format(Locale.ROOT, "https://%s.blob.core.windows.net", accountName);
    BlobServiceClient storageClient = new BlobServiceClientBuilder().credential(credential)
                                          .endpoint(endpoint).buildClient();

    BlobContainerClient container = storageClient.getBlobContainerClient(containerName)
    if ( container.exists() ) {
       // perform operation when container exists 
    }         
person Somansh Reddy    schedule 04.09.2020