web-dev-qa-db-fra.com

Renommer Blob Azure Storage

Est-il possible de renommer un blob Azure Storage à l'aide de l'API Azure Storage à partir d'un rôle Web? La seule solution que j'ai à l'heure actuelle est de copier le blob dans un nouveau blob avec le nom correct et de supprimer l'ancien.

40
Geoff

Il existe une façon pratique de le faire , bien que l'API Azure Blob Service ne prenne pas directement en charge la possibilité de renommer ou de déplacer des blobs.

28
Rinat Abdullin

METTRE À JOUR:

J'ai mis à jour le code après les commentaires de @IsaacAbrahams et la réponse de @ Viggity. Cette version devrait vous éviter de tout charger dans un MemoryStream et attend que la copie soit terminée avant de supprimer le blob source.


Pour ceux qui se rendent en retard à la soirée mais qui tombent sur cette publication à l'aide de l'API Azure Storage V2, voici une méthode d'extension Pour le faire rapidement et de manière sale (+ version asynchrone):

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

Mise à jour pour 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 Exception("Rename failed: " + target.CopyState.Status);

        await source.DeleteAsync();            
    }

Clause de non-responsabilité: Il s'agit d'une méthode rapide et incorrecte pour exécuter le renommage de manière synchrone. Cela correspond à mes besoins, cependant, comme d'autres utilisateurs l'ont noté, la copie peut prendre beaucoup de temps (jusqu'à plusieurs jours). La meilleure façon de procéder consiste donc à NE PAS utiliser cette méthode dans une méthode comme celle-ci, mais plutôt:

  • Démarrer le processus de copie
  • Interroger le statut de l'opération de copie
  • Supprimer le blob original lorsque la copie est terminée. 
38
Wiebe Tijsma

Vous pouvez cependant copier puis supprimer.

26
smarx

À l’origine, j’utilisais le code de @Zidad et fonctionnait généralement dans des conditions de charge faible (je renomme presque toujours de petits fichiers, environ 10 Ko). 

NE PAS StartCopyFromBlob alors Delete !!!!!!!!!!!!!!

Dans un scénario de forte charge, J’AI PERDU ~ 20% des fichiers que je renommais (des milliers de fichiers) . Comme mentionné dans les commentaires sur sa réponse, StartCopyFromBlob commence simplement la copie. Il n'y a aucun moyen pour vous d'attendre la fin de la copie.  

La seule façon pour vous de garantir la fin de la copie est de la télécharger et de la télécharger à nouveau. Voici mon code mis à jour: 

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

Bien que ce soit un ancien article, cet excellent article de blog montrera peut-être aux autres comment renommer très rapidement des blobs téléchargés.

Voici les faits saillants:

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

Copiez le blob, puis supprimez-le.

Testé pour des fichiers de taille 1G, et cela fonctionne bien. 

Pour plus d'informations, voir sample sur 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

Cela a fonctionné pour moi dans un environnement dynamique de 100 Ko. Les utilisateurs dont la taille de fichier ne dépasse pas 100 mb. C'est une approche synchrone similaire à la réponse de @ viggity. Mais la différence réside dans le fait qu’il copie tout du côté Azure, de sorte que vous n’avez pas à conserver Memorystream sur votre serveur pour la copie/le téléchargement dans un nouveau 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

Le seul moyen pour le moment est de déplacer le blob src vers une nouvelle destination/un nouveau nom. Voici mon code pour le faire

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

Voici un exemple de code si vous souhaitez que la recherche de blob fasse partie de la méthode:

    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

Vous pouvez maintenant avec la nouvelle version en avant-première publique de ADLS Gen 2 ( Azure Data Lake Storage Gen 2 )

La capacité Hierarchical Namespace vous permet d'effectuer une manipulation atomique de répertoires et de fichiers incluant l'opération Rename.

Notez cependant ce qui suit: "Avec la version d’aperçu, si vous activez l’espace de noms hiérarchique, les données ou opérations ne sont pas interopérables entre les API REST de Blob et Data Lake Storage Gen2. Cette fonctionnalité ajouté lors de la prévisualisation. "

Vous devrez vous assurer de créer les blobs (fichiers) à l'aide d'ADLS Gen 2 pour les renommer. Sinon, attendez que l'interopérabilité entre les API Blob et ADLS Gen 2 soit ajoutée pendant la période de prévisualisation.

0
Saher Ahwal