代码之家  ›  专栏  ›  技术社区  ›  Geoff

Azure存储Blob重命名

  •  41
  • Geoff  · 技术社区  · 14 年前

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

    9 回复  |  直到 10 年前
        1
  •  34
  •   Ofer Zelig Tom    6 年前

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

        2
  •  44
  •   Wiebe Tijsma    6 年前

    更新:

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


    扩展方法,以快速和脏(+异步版本):

    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。
        3
  •  26
  •   user94559    14 年前

    但是,您可以复制然后删除。

        4
  •  21
  •   viggity    10 年前

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

    StartCopyFromBlob 然后 Delete

    在高负荷情况下, . 正如在他回答的评论中提到的, 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();
        }
    }
    
        5
  •  12
  •   crthompson Mandrake    11 年前

    虽然这是一个老职位,也许这个 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();
    
        6
  •  4
  •   Ann Yu    8 年前

    复制blob,然后删除它。

    测试了1G大小的文件,工作正常。

    sample 在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();  
        } 
    } 
    
        7
  •  0
  •   Darrel K.    7 年前

     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
  •   Saher Ahwal    6 年前

    ADLS Gen 2 ( Azure Data Lake Storage Gen 2 )

    这个 Hierarchical Namespace 该功能允许您对目录和文件执行原子操作,其中包括 重命名 操作。

    “在预览版中,如果启用分层命名空间,Blob和datalake Storage gen2restapi之间就没有数据或操作的互操作性。预览期间将添加此功能。“

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

        9
  •  0
  •   Pleymor    4 年前
        10
  •  -2
  •   rak    8 年前

    这在10万用户的实时环境中工作,文件大小不超过100MB。这与@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();
     }
    
        11
  •  -2
  •   Bon    5 年前

    attachment;filename="yourfile.txt"
    

    通过http下载的名称将是您想要的任何名称。

    我认为存储是建立在这样一种假设的基础上的,即数据将以唯一标识符的方式存储,唯一标识符主要用作文件名。不过,为所有下载发布共享访问签名有点奇怪,所以这对某些人来说并不理想。