it-swarm.com.ru

Переименование BLOB-объекта хранилища Azure

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

40
Geoff

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

28
Rinat Abdullin

Обновление:

Я обновил код после комментариев @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();            
    }

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

  • Начать процесс копирования
  • Опрос статуса операции копирования
  • Удалите исходный BLOB-объект после завершения копирования. 
38
Wiebe Tijsma

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

26
smarx

Первоначально я использовал код из @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();
    }
}
18
viggity

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

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

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

Скопируйте блоб, затем удалите его.

Проверено на файлы размером 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();  
    } 
} 
5
Ann Yu

Это сработало для меня в живом окружении 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();
 }
0
rak

Единственный способ на данный момент - переместить объект 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
Darrelk

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

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

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

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

0
Saher Ahwal