Переименование BLOB-объекта хранилища Azure - PullRequest
41 голосов
/ 17 сентября 2010

Можно ли переименовать BLOB-объект хранилища Azure с помощью API хранилища Azure из веб-роли?Единственное решение, которое у меня есть на данный момент, - это скопировать BLOB-объект в новый BLOB-объект с правильным именем и удалить старый.

Ответы [ 9 ]

38 голосов
/ 24 января 2014

ОБНОВЛЕНИЕ:

Я обновил код после комментариев @IsaacAbrahams и ответа @ Viggity, эта версия должна препятствовать загрузке всего в MemoryStream и ждет завершения копирования перед удалением исходного большого двоичного объекта.


Для тех, кто опаздывает на вечеринку, но спотыкается на этом посте, используя Azure Storage API V2, вот метод расширения, который делает это быстро и грязно (+ асинхронная версия):

public static class BlobContainerExtensions 
{
   public static void Rename(this CloudBlobContainer container, string oldName, string newName)
   {
      //Warning: this Wait() is bad practice and can cause deadlock issues when used from ASP.NET applications
      RenameAsync(container, oldName, newName).Wait();
   }

   public static async Task RenameAsync(this CloudBlobContainer container, string oldName, string newName)
   {
      var source = await container.GetBlobReferenceFromServerAsync(oldName);
      var target = container.GetBlockBlobReference(newName);

      await target.StartCopyFromBlobAsync(source.Uri);

      while (target.CopyState.Status == CopyStatus.Pending)
            await Task.Delay(100);

      if (target.CopyState.Status != CopyStatus.Success)
          throw new Exception("Rename failed: " + target.CopyState.Status);

      await source.DeleteAsync();
    }
}

Обновление для хранилища Azure 7.0

    public static async Task RenameAsync(this CloudBlobContainer container, string oldName, string newName)
    {
        CloudBlockBlob source =(CloudBlockBlob)await container.GetBlobReferenceFromServerAsync(oldName);
        CloudBlockBlob target = container.GetBlockBlobReference(newName);


        await target.StartCopyAsync(source);

        while (target.CopyState.Status == CopyStatus.Pending)
            await Task.Delay(100);

        if (target.CopyState.Status != CopyStatus.Success)
            throw new Exception("Rename failed: " + target.CopyState.Status);

        await source.DeleteAsync();            
    }

Отказ от ответственности: Это быстрый и грязный способ заставить переименование выполняться синхронно.Это соответствует моим целям, однако, как отметили другие пользователи, копирование может занять много времени (до нескольких дней), поэтому лучше всего НЕ выполнять это одним способом, как этот ответ, а вместо этого:

  • Запустите процесс копирования
  • Опрос состояния операции копирования
  • Удалите исходный большой двоичный объект после завершения копирования.
29 голосов
/ 17 сентября 2010

Существует практический способ сделать это , хотя Azure API службы BLOB-объектов напрямую не поддерживает возможность переименовывать или перемещать BLOB-объекты.

26 голосов
/ 18 сентября 2010

Однако вы можете скопировать, а затем удалить.

18 голосов
/ 24 октября 2014

Изначально я использовал код из @Zidad, и в условиях низкой нагрузки он обычно работал (я почти всегда переименовывал небольшие файлы, ~ 10 КБ).

НЕ StartCopyFromBlob, затем Delete !!!!!!!!!!!!!!

В сценарии высокой нагрузки Я ПОТЕРЯЛ ~ 20% файлов, которые я переименовал (тысячи файлов) . Как уже упоминалось в комментариях к его ответу, StartCopyFromBlob просто запускает копию. Невозможно дождаться окончания копирования.

Единственный способ гарантировать завершение копии - это загрузить ее и загрузить заново. Вот мой обновленный код:

public void Rename(string containerName, string oldFilename, string newFilename)
{
    var oldBlob = GetBlobReference(containerName, oldFilename);
    var newBlob = GetBlobReference(containerName, newFilename);

    using (var stream = new MemoryStream())
    {
        oldBlob.DownloadToStream(stream);
        stream.Seek(0, SeekOrigin.Begin);
        newBlob.UploadFromStream(stream);

        //copy metadata here if you need it too

        oldBlob.Delete();
    }
}
12 голосов
/ 02 августа 2013

Хотя это старая запись, возможно, эта отличная запись в блоге покажет другим, как очень быстро переименовать загруженные объекты.

Вот основные моменты:

//set the azure container
string blobContainer = "myContainer";
//azure connection string
string dataCenterSettingKey = string.Format("DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}", "xxxx",
                                            "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
//setup the container object
CloudStorageAccount cloudStorageAccount = CloudStorageAccount.Parse(dataCenterSettingKey);
CloudBlobClient blobClient = cloudStorageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference(blobContainer);

// Set permissions on the container.
BlobContainerPermissions permissions = new BlobContainerPermissions();
permissions.PublicAccess = BlobContainerPublicAccessType.Blob;
container.SetPermissions(permissions);

//grab the blob
CloudBlob existBlob = container.GetBlobReference("myBlobName");
CloudBlob newBlob = container.GetBlobReference("myNewBlobName");
//create a new blob
newBlob.CopyFromBlob(existBlob);
//delete the old
existBlob.Delete();
5 голосов
/ 16 августа 2016

Скопируйте большой двоичный объект, затем удалите его.

Проверено на файлы размером 1G, и работает нормально.

Для получения дополнительной информации см. образец в MSDN.

StorageCredentials cred = new StorageCredentials("[Your?storage?account?name]", "[Your?storage?account?key]");  
CloudBlobContainer container = new CloudBlobContainer(new Uri("http://[Your?storage?account?name].blob.core.windows.net/[Your container name] /"), cred);  

string fileName = "OldFileName";  
string newFileName = "NewFileName";  
await container.CreateIfNotExistsAsync();  

CloudBlockBlob blobCopy = container.GetBlockBlobReference(newFileName);  

if (!await blobCopy.ExistsAsync())  
{  
    CloudBlockBlob blob = container.GetBlockBlobReference(fileName);  

    if (await blob.ExistsAsync())  
    {  
           // copy
           await blobCopy.StartCopyAsync(blob);                               
           // then delete
           await blob.DeleteIfExistsAsync();  
    } 
} 
0 голосов
/ 07 июля 2018

Теперь вы можете с новым выпуском публичного предварительного просмотра ADLS Gen 2 ( Azure Data Lake Storage Gen 2 )

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

Однако обратите внимание на следующее: «В предварительном выпуске, если вы включите иерархическое пространство имен, взаимодействие между данными или операциями между API-интерфейсами REST Blob и Data Lake Storage Gen2 не будет. Эта функциональность будет добавлена ​​во время предварительного просмотра».

Вам нужно будет убедиться, что вы создаете BLOB-объекты (файлы), используя ADLS Gen 2 для их переименования. В противном случае дождитесь возможности взаимодействия между API-интерфейсами BLOB-объектов и ADLS Gen 2 в течение периода предварительного просмотра.

0 голосов
/ 23 ноября 2017

Единственный способ на данный момент состоит в том, чтобы переместить каплю src в новое место назначения / имя. Вот мой код, чтобы сделать это

 public async Task<CloudBlockBlob> RenameAsync(CloudBlockBlob srcBlob, CloudBlobContainer destContainer,string name)
    {
        CloudBlockBlob destBlob;

        if (srcBlob == null && srcBlob.Exists())
        {
            throw new Exception("Source blob cannot be null and should exist.");
        }

        if (!destContainer.Exists())
        {
            throw new Exception("Destination container does not exist.");
        }

        //Copy source blob to destination container            
        destBlob = destContainer.GetBlockBlobReference(name);
        await destBlob.StartCopyAsync(srcBlob);
        //remove source blob after copy is done.
        srcBlob.Delete();
        return destBlob;
    }

Вот пример кода, если вы хотите, чтобы поиск BLOB-объектов был частью метода:

    public CloudBlockBlob RenameBlob(string oldName, string newName, CloudBlobContainer container)
    {
        if (!container.Exists())
        {
            throw new Exception("Destination container does not exist.");
        }
        //Get blob reference
        CloudBlockBlob sourceBlob = container.GetBlockBlobReference(oldName);

        if (sourceBlob == null && sourceBlob.Exists())
        {
            throw new Exception("Source blob cannot be null and should exist.");
        }

        // Get blob reference to which the new blob must be copied
        CloudBlockBlob destBlob = container.GetBlockBlobReference(newName);
        destBlob.StartCopyAsync(sourceBlob);

        //Delete source blob
        sourceBlob.Delete();
        return destBlob;
    }
0 голосов
/ 06 сентября 2016

Это сработало для меня в живом окружении 100K пользователей с размером файла не более 100 мб.Это похоже на синхронный подход к ответу @ viggity.Но разница в том, что он копирует все на стороне Azure, поэтому вам не нужно хранить Memorystream на вашем сервере для копирования / загрузки в новый BLOB-объект.

 var account = new CloudStorageAccount(new Microsoft.WindowsAzure.Storage.Auth.StorageCredentials(StorageAccountName, StorageAccountKey), true);
 CloudBlobClient blobStorage = account.CreateCloudBlobClient();
 CloudBlobContainer container = blobStorage.GetContainerReference("myBlobContainer");

 string fileName = "OldFileName";  
 string newFileName = "NewFileName"; 

 CloudBlockBlob oldBlob = container.GetBlockBlobReference(fileName);
 CloudBlockBlob newBlob = container.GetBlockBlobReference(newFileName);
 using (var stream = new MemoryStream())
 {
      newBlob.StartCopyFromBlob(oldBlob);
      do { } while (!newBlob.Exists());
      oldBlob.Delete();
 }
...