Подтвердить что ты не робот

Azure Storage Blob Переименовать

Можно ли переименовать Azure Storage Blob с использованием Azure Storage API из веб-роли? Единственное решение, которое у меня есть на данный момент, - скопировать blob в новый blob с правильным именем и удалить старый.

4b9b3361

Ответ 1

В настоящее время невозможно переименовать blob за одну операцию.

Azure API службы Blob не поддерживает возможность переименовывать или перемещать капли.

Ответ 2

UPDATE:

Я обновил код после комментариев @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 ApplicationException("Rename failed: " + target.CopyState.Status);

      await source.DeleteAsync();
    }
}

Обновление для Azure Storage 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 ApplicationException("Rename failed: " + target.CopyState.Status);

        await source.DeleteAsync();            
    }

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

  • Запустить процесс копирования
  • Опросить состояние операции копирования
  • Удалить копию оригинала, когда копия завершена.

Ответ 3

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

Ответ 4

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

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

В сценарии с высокой нагрузкой я LOST ~ 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();
    }
}

Ответ 5

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

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

//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();

Ответ 6

Скопируйте blob и удалите его.

Протестировано для файлов размером 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();  
    } 
} 

Ответ 7

Это работало для меня в живой среде пользователей 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();
 }

Ответ 8

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

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