c# - images - azure storage sdk
Azure Storage Blob Rename (9)
¿Es posible cambiar el nombre de una Blob de almacenamiento de Azure utilizando Azure Storage API 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.
ACTUALIZAR:
Actualicé el código después de los comentarios de @IsaacAbrahams y la respuesta de @Viggity, esta versión debe evitar que tenga que cargar todo en un MemoryStream, y espera hasta que la copia se complete antes de eliminar el blob de origen.
Para cualquiera que llegue tarde a la fiesta pero se tropiece con esta publicación usando Azure Storage API V2, aquí hay un método de extensión para hacerlo rápido y sucio (versión + async):
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();
}
Descargo de responsabilidad: Este es un método rápido y sucio para hacer que el rename se ejecute de forma síncrona. Se ajusta a mis propósitos, sin embargo, como otros usuarios señalaron, la copia puede llevar mucho tiempo (hasta días), por lo que la mejor manera es NO realizar esto en 1 método como esta respuesta, sino en su lugar:
- Comience el proceso de copia
- Encuesta el estado de la operación de copia
- Borre el blob original cuando se complete la copia.
Ahora puede obtener el nuevo lanzamiento en la vista previa pública de ADLS Gen 2 ( Azure Data Lake Storage Gen 2 )
La capacidad del docs.microsoft.com/en-us/azure/storage/data-lake-storage/… permite realizar la manipulación atómica de directorios y archivos que incluye la operación Renombrar .
Sin embargo, tome nota de lo siguiente: "Con la versión preliminar, si habilita el espacio de nombres jerárquico, no hay interoperabilidad de datos u operaciones entre las API REST de Blob y Data Lake Storage Gen2. Esta funcionalidad se agregará durante la vista previa".
Deberá asegurarse de crear los blobs (archivos) usando ADLS Gen 2 para cambiarles el nombre. De lo contrario, espere a que se agregue la interoperabilidad entre las API de Blob y ADLS Gen 2 durante el período de vista previa.
Copie el blob, 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();
}
}
Esto funcionó para mí en un entorno en vivo de 100 mil usuarios con tamaños de archivo de 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();
}
La única forma 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í hay un ejemplo de código si desea la búsqueda 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;
}
Originalmente usé el código de @Zidad, y en circunstancias de poca carga usualmente funcionaba (casi siempre cambio el nombre de archivos pequeños, ~ 10kb).
NO StartCopyFromBlob
then Delete
!!!!!!!!!!!!!!
En un escenario de carga alta, PERDIÉ ~ 20% de los archivos que estaba cambiando de nombre (miles de archivos) . Como se mencionó en los comentarios sobre su respuesta, StartCopyFromBlob
solo comienza la copia. No hay forma de que esperes a que termine la copia.
La única manera de garantizar que la copia termine es descargarla y volver a subirla. 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();
}
}
Por el momento, es imposible cambiar el nombre de blob en una operación .
La API de Azure Blob Service no admite la capacidad de cambiar el nombre o mover blobs.
Si bien esta es una publicación anterior, tal vez esta excelente publicación de blog mostrará a otros cómo cambiar rápidamente el nombre de las manchas que se han subido.
Estos 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();
Sin embargo, puede copiar y luego eliminar.