2010-09-17 21 views
32

¿Es posible cambiar el nombre de una Blob de almacenamiento de Azure utilizando la API de almacenamiento de Azure desde un rol web? La única solución que tengo en este momento es copiar el blob a un nuevo blob con el nombre correcto y eliminar el anterior.Cambio de nombre de bloque de almacenamiento en Azure

Respuesta

25

En este momento es imposible cambiar el nombre de blob en una operación.

Azure Blob Service API no admite la capacidad de cambiar el nombre o mover blobs.

25

Sin embargo, puede copiar y luego eliminar.

+7

si copia, asegúrese de copiar los datos reales y los metadatos , ENTONCES eliminar. NO use StartCopyFromBlob y luego Delete. Perdí el 20% de mis archivos. Estaba renombrando porque la Copia no terminó antes de que la operación de borrado surta efecto. http://stackoverflow.com/questions/3734672/azure-storage-blob-rename/26549519#26549519 – viggity

12

Si bien esta es una publicación anterior, quizás esta excellent blog post mostrará a otros cómo cambiar rápidamente el nombre de las manchas que se han subido.

Éstos son los aspectos más destacados:

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

Considere actualizar su respuesta con un breve resumen de los puntos relevantes. Entonces seguirá siendo útil para otros, incluso si el enlace se rompe. – Leigh

+4

Por lo que puedo decir, esto está desactualizado a partir de Azure Storage API 2 ... Ahora CopyFromBlob se ha convertido en StartCopyFromBlob, y estoy enterado de que esto pone su blob en una cola de cambio de nombre que puede tomar como máximo 7 días. –

+0

que no ha sido mi experiencia. Si bien puede decir algo como eso en el SLA, es muy rápido para crear y copiar. – paqogomez

34

ACTUALIZACIÓN:

He actualizado el código después de @IsaacAbrahams comentarios y @ respuesta de Viggity, esta versión se le impide tener que cargar todo en un MemoryStream, y Espera hasta que se complete la copia antes de eliminar el blob de origen.


Para cualquier persona haciendo tarde a la fiesta, pero tropezando sobre esta entrada utilizando Azure Storage API V2, aquí está un método extensión para hacerlo rápido y sucio (+ asíncrono versión):

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

Actualización para 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();    
    } 

responsabilidad: Este es un método rápido y sucio para hacer el cambio de nombre de ejecutar una forma sincrónica. Se ajusta a mis propósitos, sin embargo, como señalaron otros usuarios, la copia puede tardar mucho tiempo (hasta días), por lo que la mejor manera es no llevar a cabo esto en 1 método como este respuesta, pero en su lugar:

  • de iniciar la copia proceso
  • Encuestar el estado de la operación de copia
  • Eliminar el blob original cuando se completa la copia.
+1

@BrianMacKay mencionó que el 'StartCopyFromBlob' puede tardar 7 días en completarse. ¿Hay algo de cierto en eso por lo que usted sabe? – paqogomez

+1

Hola @Paqogomez, tal vez de acuerdo con el SLA en algún lugar, pero en mi experiencia es rápido (en el rango de milisegundos a segundos) –

+1

AFAIK StartCopyFromBlob volverá cuando la operación de copia haya STARTED. ¡No volverá cuando la copia esté completa! Para identificar cuándo se realiza la operación de copia, debe sondear las últimas propiedades del blob y ver cuándo se completó la operación de copia. –

17

Originalmente utilicé el código de @Zidad, y en circunstancias de poca carga usualmente funcionaba (casi siempre cambio el nombre de archivos pequeños, ~ 10kb).

DO NO StartCopyFromBlob luego Delete !!!!!!!!!!!!!!

En un escenario de carga alta, perdí ~ 20% de los archivos que estaba el cambio de nombre (miles de archivos). Como se menciona en los comentarios sobre su respuesta, StartCopyFromBlob acaba de comenzar la copia. No hay forma de que espere a que termine la copia.

La única forma de garantizar los finales de copia es descargarlo y volver a subirlo.Aquí está mi código actualizado:

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

Hola, Viggity, gracias, parece que @IsaacAbraham tenía razón, lo siento. He actualizado mi respuesta con una advertencia. –

+1

Aparentemente hay un estado que también puedes verificar que te permitirá cambiar el nombre del blob sin tener que descargarlo todo en la memoria como lo haces, actualizaré mi respuesta ... –

+0

@zidad, enfoque interesante. en mi caso particular, no quiero que sea asincrónico, ya que podría manguera un par de otras cosas. Gracias por la actualización. – viggity

5

Copie el blob y luego bórrelo.

Probado para archivos de tamaño 1G, y funciona bien.

Para obtener más información, vea el sample en 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

Esto funcionó para mí en el entorno real de 100K Los usuarios que tienen tamaños de archivo no más de 100 mb. Este es un enfoque sincrónico similar a la respuesta de @viggity. Pero la diferencia es que está copiando todo en el lado Azure para que no tenga que mantener Memorystream en su servidor para Copiar/Cargar en Blob nuevo.

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

¿Por qué está utilizando un nuevo MemorySteam al que nunca se hace referencia? – kspearrin

+0

Lo siento, bifurqué ese código de la respuesta de @ viggity y olvidé eliminar esa referencia. Pero puede hacerse una idea de cómo se puede hacer en el lado del servidor. – rak

0

La única manera de hacerlo es mover la burbuja src a un nuevo destino/nombre. Aquí está mi código para hacer esto

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

Aquí está un ejemplo de código si desea que la consulta de blob como parte del método:

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