Kann ein Azure Storage Blob mithilfe der Azure Storage API von einer Webrolle aus umbenannt werden? Die einzige Lösung, die ich momentan habe, ist, den Blob in einen neuen Blob mit dem richtigen Namen zu kopieren und den alten zu löschen.
Es gibt einen praktischen Weg dazu , obwohl Azure Blob Service API die Fähigkeit zum Umbenennen oder Verschieben von Blobs nicht direkt unterstützt.
AKTUALISIEREN:
Ich habe den Code nach den Kommentaren von @IsaacAbrahams und der Antwort von @ Viggity aktualisiert. Diese Version sollte verhindern, dass Sie alles in einen MemoryStream laden müssen, und wartet, bis der Kopiervorgang abgeschlossen ist, bevor Sie den Quell-Blob löschen.
Für alle, die sich verspätet auf die Party begeben, aber mit Azure Storage API V2 über diesen Beitrag stolpern, finden Sie hier eine Erweiterungsmethode , Um es schnell und schmutzig zu machen (+ async-Version):
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();
}
}
Update für 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();
}
Haftungsausschluss: Dies ist eine schnelle und fehlerhafte Methode, um die Umbenennung synchron auszuführen. Es passt zu meinen Zwecken. Wie andere Benutzer bereits sagten, kann das Kopieren jedoch sehr lange dauern (bis zu einigen Tagen). Daher ist es am besten, diese Methode NICHT in einer Methode wie dieser Antwort auszuführen, sondern stattdessen:
Sie können jedoch kopieren und dann löschen.
Ich habe ursprünglich Code von @Zidad verwendet, und unter niedrigen Lastbedingungen hat es normalerweise funktioniert (ich benenne fast immer kleine Dateien um, ~ 10kb).
NICHT StartCopyFromBlob
dann Delete
!!!!!!!!!!!!!!
In einem Szenario mit hoher Auslastung hat I LOST ~ 20% der Dateien, die ich umbenannt habe (Tausende von Dateien) . Wie in den Kommentaren zu seiner Antwort erwähnt, startet StartCopyFromBlob
einfach die Kopie. Es gibt keine Möglichkeit für Sie zu warten, bis die Kopie fertig ist.
Sie können nur garantieren, dass die Kopie fertig ist, indem Sie sie herunterladen und erneut hochladen. Hier ist mein aktualisierter Code:
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();
}
}
Während dies ein alter Beitrag ist, wird dieser ausgezeichneter Blogbeitrag vielleicht anderen zeigen, wie Blobs, die hochgeladen wurden, sehr schnell umbenannt werden können.
Hier sind die Highlights:
//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();
Kopieren Sie den Blob und löschen Sie ihn.
Getestet für Dateien der Größe 1G, und es funktioniert OK.
Weitere Informationen finden Sie im sample in 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();
}
}
Dies funktionierte für mich in einer Live-Umgebung von 100.000 Benutzern mit einer Dateigröße von nicht mehr als 100 MB. Dies ist ein ähnlicher synchroner Ansatz wie bei der Antwort von @viggity. Der Unterschied ist jedoch, dass alles auf Azure-Seite kopiert wird, sodass Sie Memorystream nicht auf Ihrem Server speichern müssen, um in neuen Blob kopieren/hochladen zu können.
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();
}
Wenn Sie die ContentDisposition-Eigenschaft mit festlegen
attachment;filename="yourfile.txt"
Der Name des Downloads über http ist beliebig.
Ich denke, Storage wurde mit der Annahme erstellt, dass Daten auf eine Art und Weise gespeichert werden, bei der eindeutige Bezeichner in erster Linie als Dateinamen verwendet werden. Das Ausgeben von Shared Access-Signaturen für alle Downloads ist allerdings etwas seltsam, weshalb dies für manche Menschen nicht ideal ist.
Ich halte es jedoch für eine gute Praxis, den benutzerbezogenen Dateinamen zu entfernen, und ermutige insgesamt zu einer stabileren Architektur.
Momentan ist die einzige Möglichkeit, den src-Blob an ein neues Ziel/einen neuen Namen zu verschieben. Hier ist mein Code, um dies zu tun
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;
}
Hier ein Codebeispiel, wenn Sie die Blob-Suche als Teil der Methode wünschen:
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;
}
Sie können jetzt mit der neuen Version in der öffentlichen Vorschau von ADLS Gen 2 ( Azure Data Lake Storage Gen 2 )
Mit der Funktion Hierarchical Namespace können Sie Verzeichnisse und Dateien atomar bearbeiten, einschließlich der Operation Rename .
Beachten Sie jedoch Folgendes: "Wenn Sie mit dem Preview-Release den hierarchischen Namespace aktivieren, besteht keine Interoperabilität der Daten oder Operationen zwischen Blob und Data Lake Storage Gen2 REST-APIs. Diese Funktionalität wird während der Vorschau hinzugefügt. "
Sie müssen sicherstellen, dass Sie die Blobs (Dateien) mit ADLS Gen 2 erstellen, um sie umzubenennen. Warten Sie andernfalls, bis die Interoperabilität zwischen Blob-APIs und ADLS Gen 2 während des Vorschauzeitraums hinzugefügt wird.