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

131

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

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

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

Ответы:

203

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

public static bool BlobExistsOnCloud(CloudBlobClient client, 
    string containerName, string key)
{
     return client.GetContainerReference(containerName)
                  .GetBlockBlobReference(key)
                  .Exists();  
}
Ричард
источник
6
Есть .. версия на питоне?
anpatel
2
Интересно, сколько вам нужно заплатить за проверку существования BLOB-объекта? Этот способ defo кажется лучшим вариантом, чем попытка загрузить blob.
DermFrench
10
@anpatel, версия для python:len(blob_service.list_blobs(container_name, file_name)) > 0
RaSi
3
вы можете обновить свой ответ,
указав,
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 для большого двоичного объекта.

user94559
источник
1
FetchAttributes () требует много времени для запуска (по крайней мере, в хранилище разработки), если файл еще не был полностью зафиксирован, т.е. просто состоит из незафиксированных блоков.
Том Робинсон
7
Если вы все равно собираетесь получить BLOB-объект, как намеревается OP, почему бы не попробовать загрузить контент прямо сейчас? Если его там нет, он выдаст так же, как FetchAttributes. Выполнение этой проверки в первую очередь - это просто дополнительный запрос, или я что-то упустил?
Марникс ван Вален,
Марникс делает отличное заявление. Если вы все равно собираетесь его скачать, просто попробуйте скачать.
user94559
@Marnix: если вы вызовете что-то подобное, OpenReadон не будет генерировать или возвращать пустой поток или что- то в этом роде . Вы получите ошибки только тогда, когда начнете скачивать с него.
Намного
1
@Porges: разработка облачного приложения - это «дизайн на случай отказа». Сейчас ведется много дискуссий о том, как правильно справиться с этой ситуацией. Но в целом - я бы просто пошел и загрузил его, а затем обработал отсутствующие ошибки Blob. Не только это, но и если я собираюсь проверять наличие каждого большого двоичного объекта, я увеличиваю количество транзакций хранилища, следовательно, мой счет. У вас все еще может быть одно место для обработки исключений / ошибок.
astaykov
16

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

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

judell
источник
5

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

Доступен как пакет NuGet.
Создан: Microsoft
Id: WindowsAzure.Storage
Version: 2.0.5.1.

См. Также msdn

huha
источник
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
emert117
источник
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 является синхронным, использование await заставляет ExistsAsync также быть синхронным. Итак, я согласен с тем, что HTTP-вызовы обычно должны быть асинхронными. Но этот код не тот. Тем не менее, +1 за новый API!
Ричард
2
Спасибо, но больше не могу не согласиться. Exists()является синхронным в том смысле, что он блокирует поток до его завершения. await ExistsAscyn()является асинхронным в том смысле, что это не так. Оба следуют одному и тому же логическому потоку: следующая строка кода не начинается до тех пор, пока не будет завершена предыдущая, но именно неблокирующая природа ExistsAsyncделает ее асинхронной.
Тодд Менье
1
И ... я узнал кое-что новое! :) softwareengineering.stackexchange.com/a/183583/38547
Ричард
1

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

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

Я получаю объект 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;
        }
    }
}

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

Zaehos
источник
0

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

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

Джалия Удагедара
источник