Azure存储Blob重命名

时间:2010-09-17 10:49:39

标签: c# azure azure-storage

是否可以从Web角色使用Azure存储API重命名Azure存储Blob?我目前唯一的解决方案是将blob复制到具有正确名称的新blob并删除旧的blob。

13 个答案:

答案 0 :(得分:38)

更新:

我在@IsaacAbrahams评论和@Viggity的回答之后更新了代码,这个版本应该可以防止您必须将所有内容加载到MemoryStream中,并在删除源blob之前等待副本完成。


对于任何迟到的人,但使用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 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();            
    }

免责声明:这是一种快速而又脏的方法,可以使重命名以同步方式执行。它符合我的目的,但正如其他用户所说,复制可能需要很长时间(最多几天),所以最好的方法是不要像这个答案那样在1方法中执行此操作,而是:

  • 开始复制过程
  • 轮询复制操作的状态
  • 复制完成后删除原始blob。

答案 1 :(得分:28)

practical way to do so,但Azure Blob Service API不直接支持重命名或移动blob的功能。

答案 2 :(得分:26)

然而,您可以复制然后删除。

答案 3 :(得分:18)

我最初使用来自@Zidad的代码,并且在低负载情况下它通常有效(我几乎总是重命名小文件,~10kb)。

请勿StartCopyFromBlob然后Delete !!!!!!!!!!!!!!

在高负载情况下, I LOST~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();
    }
}

答案 4 :(得分:12)

虽然这是一篇旧帖子,但也许这个excellent blog post会向其他人展示如何快速重命名已上传的blob。

以下是重点:

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

答案 5 :(得分:5)

复制blob,然后将其删除。

测试了1G大小的文件,它运行正常。

有关详细信息,请参阅MSDN上的sample

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

答案 6 :(得分:0)

这适用于100K用户的实时环境,文件大小不超过100 MB。这与@ 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();
 }

答案 7 :(得分:0)

唯一的方法是将src blob移动到新的目的地/名称。这是我的代码

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

答案 8 :(得分:0)

您现在可以在ADLS Gen 2Azure Data Lake Storage Gen 2)的公共预览中使用新版本

借助Hierarchical Namespace功能,您可以对目录和文件执行原子操作,其中包括重命名操作。

但是,请注意以下几点: “在预览版本中,如果启用了分层名称空间,则Blob和Data Lake Storage Gen2 REST API之间将不存在数据或操作的互操作性。此功能将在预览期间添加。”

您需要确保使用ADLS Gen 2创建重命名Blob(文件)。否则,请等待在预览时间段内添加Blob API和ADLS Gen 2之间的互操作性。

答案 9 :(得分:0)

还有一种方法无需复制您的Blob以对其进行重命名,也无需运行任何脚本:将Azure Blob存储安装到您的操作系统:https://docs.microsoft.com/bs-latn-ba/azure/storage/blobs/storage-how-to-mount-container-linux

然后,您只需使用mv,您的Blob将立即重命名。

答案 10 :(得分:0)

使用 Monza Cloud 的 Azure Explorer,我可以在一秒钟内重命名一个 18 GB 的 blob。微软的 Azure 存储资源管理器需要 29 秒来克隆同一个 blob,所以蒙扎不是 做副本。我知道它很快,因为在 Monza 重命名后,单击 Microsoft Azure 存储资源管理器中的容器立即显示具有新名称的 blob。

答案 11 :(得分:0)

使用 Azure 存储资源管理器是手动重命名 blob 的最简单方法。您可以在此处下载https://azure.microsoft.com/en-us/features/storage-explorer/#overview

答案 12 :(得分:-1)

如果使用

设置ContentDisposition属性
attachment;filename="yourfile.txt"

您可以通过http下载的名称。

我认为存储是在假设数据将以唯一用作文件名的唯一标识符的方式存储的前提下构建的。不过,为所有下载发布共享访问签名有点奇怪,因此对于某些人来说并不理想。

但是我认为抽象出面向用户的文件名总体上是一个好习惯,并且总体上鼓励了更稳定的体系结构。