Memeriksa apakah ada gumpalan di Azure Storage

131

Saya punya pertanyaan yang sangat sederhana (saya harap!) - Saya hanya ingin mencari tahu apakah gumpalan (dengan nama yang saya definisikan) ada di wadah tertentu. Saya akan mengunduhnya jika memang ada, dan jika tidak, saya akan melakukan hal lain.

Saya telah melakukan beberapa pencarian di intertubes dan tampaknya dulu ada fungsi yang disebut DoesExist atau yang serupa ... tetapi karena dengan begitu banyak Azure API, ini tampaknya tidak lagi ada di sana (atau jika ada, memiliki nama yang sangat cerdik).

John
sumber
Terimakasih semuanya. Karena saya menggunakan StorageClient (dan akan lebih memilih untuk menjaga semua akses Azure Storage saya melalui perpustakaan itu), saya menggunakan metode FetchAttributes-and-check-for-exception yang disarankan smarx. Memang 'terasa' agak aneh, karena saya tidak suka memiliki pengecualian yang dilemparkan sebagai bagian normal dari logika bisnis saya - tetapi mudah-mudahan ini dapat diperbaiki dalam versi StorageClient di masa mendatang :)
John

Jawaban:

202

API baru memiliki panggilan fungsi .Exists (). Pastikan Anda menggunakan GetBlockBlobReference, yang tidak melakukan panggilan ke server. Itu membuat fungsinya semudah:

public static bool BlobExistsOnCloud(CloudBlobClient client, 
    string containerName, string key)
{
     return client.GetContainerReference(containerName)
                  .GetBlockBlobReference(key)
                  .Exists();  
}
Richard
sumber
6
Apakah ada .. versi ... python?
anpatel
2
Bertanya-tanya apa yang Anda dapat biaya untuk memeriksa gumpalan yang ada? Defo ini sepertinya cara yang lebih baik daripada mencoba mengunduh gumpalan.
DermFrench
10
@anpatel, versi python:len(blob_service.list_blobs(container_name, file_name)) > 0
RaSi
3
Anda dapat memperbarui jawaban Anda dengan paket nuget mana yang harus diinstal
batmaci
9
CATATAN: Pada Microsoft.WindowsAzure.Storage versi 8.1.4.0 (.Net Framework v4.6.2) metode Exists () tidak ada yang mendukung ExistsAsync () Yang merupakan versi yang akan diinstal untuk proyek .NetCore
Adam Hardy
49

Catatan: Jawaban ini sudah usang sekarang. Silakan lihat jawaban Richard untuk cara mudah memeriksa keberadaan

Tidak, Anda tidak melewatkan sesuatu yang sederhana ... kami melakukan pekerjaan yang baik untuk menyembunyikan metode ini di pustaka StorageClient baru. :)

Saya baru saja menulis posting blog untuk menjawab pertanyaan Anda: http://blog.smarx.com/posts/testing-existence-of-a-windows-azure-blob .

Jawaban singkatnya adalah: gunakan CloudBlob.FetchAttributes (), yang melakukan permintaan HEAD terhadap gumpalan.

pengguna94559
sumber
1
FetchAttributes () membutuhkan waktu lama untuk dijalankan (setidaknya dalam pengembangan penyimpanan) jika file belum sepenuhnya berkomitmen, yaitu hanya terdiri dari blok yang tidak dikomit.
Tom Robinson
7
Jika Anda akan tetap mengambil gumpalan seperti yang ingin dilakukan OP, mengapa tidak mencoba dan mengunduh kontennya segera? Jika tidak ada, ia akan melempar seperti FetchAttributes. Melakukan pemeriksaan ini terlebih dahulu hanyalah permintaan tambahan, atau apakah saya melewatkan sesuatu?
Marnix van Valen
Marnix membuat poin yang bagus. Jika Anda tetap ingin mengunduhnya, coba unduh saja.
user94559
@Marnix: Jika Anda memanggil sesuatu seperti OpenReaditu tidak akan membuang atau mengembalikan Stream kosong atau semacamnya. Anda hanya akan mendapatkan kesalahan saat mulai mengunduh darinya. Jauh lebih mudah menangani semua ini di satu tempat :)
porges
1
@Porges: merancang aplikasi cloud adalah tentang "desain untuk kegagalan". Ada banyak diskusi bagaimana menangani situasi ini dengan benar. Tetapi secara umum - saya juga akan pergi dan mengunduhnya, kemudian menangani kesalahan Blob yang hilang. Bukan hanya itu, tetapi jika saya akan memeriksa keberadaan setiap gumpalan saya meningkatkan jumlah transaksi penyimpanan, maka tagihan saya. Anda masih dapat memiliki satu tempat untuk menangani Pengecualian / Kesalahan.
astaykov
16

Tampaknya lumpuh bahwa Anda perlu menangkap pengecualian untuk mengujinya gumpalan itu ada.

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

Jika gumpalan itu bersifat publik, Anda dapat, tentu saja, hanya mengirim permintaan HTTP HEAD - dari berbagai bahasa / lingkungan / platform yang mengetahui bagaimana melakukannya - dan memeriksa responsnya.

API Azure inti adalah antarmuka HTTP berbasis XML yang tenang. Perpustakaan StorageClient adalah salah satu dari banyak pembungkus di sekitarnya. Berikut ini yang dilakukan Sriram Krishnan dengan Python:

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

Ini juga menunjukkan cara mengotentikasi di tingkat HTTP.

Saya telah melakukan hal yang sama untuk diri saya sendiri di C #, karena saya lebih suka melihat Azure melalui lensa HTTP / REST daripada melalui lensa perpustakaan StorageClient. Untuk beberapa waktu saya bahkan tidak repot-repot menerapkan metode ExistsBlob. Semua gumpalan saya bersifat publik, dan itu sepele untuk melakukan HTTP HEAD.

Judell
sumber
5

Windows Azure Storage Library baru sudah berisi metode Exist (). Ada di Microsoft.WindowsAzure.Storage.dll.

Tersedia sebagai Paket NuGet
Dibuat oleh: Microsoft
Id: WindowsAzure.
Versi Penyimpanan: 2.0.5.1

Lihat juga msdn

huha
sumber
2

Jika Anda tidak suka menggunakan metode pengecualian, maka versi dasar c # yang disarankan judell ada di bawah ini. Namun berhati-hatilah bahwa Anda benar-benar harus menangani kemungkinan tanggapan lain juga.

HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create(url);
myReq.Method = "HEAD";
HttpWebResponse myResp = (HttpWebResponse)myReq.GetResponse();
if (myResp.StatusCode == HttpStatusCode.OK)
{
    return true;
}
else
{
    return false;
}
Gila Pierre
sumber
4
HttpWebRequest.GetResponse melempar pengecualian jika ada 404. Jadi saya tidak melihat bagaimana kode Anda akan menghindari kebutuhan untuk menangani pengecualian?
Nitramk
Titik adil. Sepertinya sampah bagi saya bahwa GetResponse () melempar pada saat itu! Saya berharap untuk mengembalikan 404 karena itu adalah responsnya !!!
Mad Pierre
2

Jika gumpalan Anda bersifat publik dan Anda hanya perlu metadata:

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

Ini adalah cara saya melakukannya. Menampilkan kode lengkap untuk mereka yang membutuhkannya.

        // 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
sumber
1

Meskipun sebagian besar jawaban di sini benar secara teknis, sebagian besar contoh kode membuat panggilan sinkron / memblokir. Kecuali Anda terikat oleh platform atau basis kode yang sangat lama, panggilan HTTP harus selalu dilakukan secara asinkron, dan SDK mendukung sepenuhnya dalam hal ini. Cukup gunakan ExistsAsync()saja Exists().

bool exists = await client.GetContainerReference(containerName)
    .GetBlockBlobReference(key)
    .ExistsAsync();
Todd Menier
sumber
Anda benar, .Exists () lama bukanlah pilihan terbaik. Namun, sementara API lama sinkron, menggunakan menunggu menyebabkan ExistsAsync juga sinkron. Jadi, saya setuju bahwa panggilan HTTP biasanya tidak sinkron. Tetapi kode ini bukan itu. Namun, +1 untuk API baru!
Richard
2
Terima kasih, tetapi saya tidak bisa tidak setuju lagi. Exists()sinkron karena memblokir utas sampai selesai. await ExistsAscyn()asinkron karena tidak. Keduanya mengikuti alur logis yang sama di mana baris kode berikutnya tidak dimulai sampai yang sebelumnya selesai, tetapi sifat nonblocking ExistsAsyncyang membuatnya asinkron.
Todd Menier
1
Dan ... Saya telah belajar sesuatu yang baru! :) softwareengineering.stackexchange.com/a/183583/38547
Richard
1

Inilah solusi yang berbeda jika Anda tidak menyukai solusi yang lain:

Saya menggunakan paket NuGet Azure.Storage.Blobs versi 12.4.1.

Saya mendapatkan objek Azure.Pageable yang merupakan daftar semua gumpalan dalam sebuah wadah. Saya kemudian memeriksa apakah nama BlobItem sama dengan properti Name dari masing-masing gumpalan di dalam wadah menggunakan LINQ . (Jika semuanya valid, tentu saja)

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

Semoga ini membantu seseorang di masa depan.

Zaehos
sumber