如何从 Blob 存储中复制文件夹?

Posted

技术标签:

【中文标题】如何从 Blob 存储中复制文件夹?【英文标题】:How to copy folders from blob storage? 【发布时间】:2021-06-15 14:50:48 【问题描述】:

我试图实现的功能是将粘贴文件/文件夹从一个源复制到另一个(相同的容器)。我可以使用与复制文件相同的方法来复制文件夹吗? startcopyblob() 在复制粘贴文件夹时抛出错误。

输入:

newFileName:'新文件夹_copy1' 新文件路径:'603487d1e966a91fd86b6c11/spe9_rs_2021-03-17_17-14-38/输出' oldFilePath:'603487d1e966a91fd86b6c11/spe9_rs_2021-02-23_11-14-41/output/新文件夹'

错误:

code:'CannotVerifyCopySource'
message:'The specified blob does not exist.
name:'StorageError'
requestId:'4a8a76bf-701e-0078-17c8-1b4439000000'
stack:'StorageError: The specified blob does not exist.
statusCode:404

Uncaught Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

代码:

var host = sasurl.substring(0, sasurl.lastIndexOf("/"));
var containerName = sasurl.substring(sasurl.lastIndexOf("/"), sasurl.indexOf("?")).split("/")[1];
var saskey = sasurl.substring(sasurl.indexOf("?"), sasurl.length);
var blobService = storage.createBlobServiceWithSas(host, saskey);
pasteFiles.forEach(elem => 
var storageuri = host + "/" + containerName + "/" + elem["oldFilePath"] + saskey;
var blobName = elem["newFilePath"] + "/" + elem["newFileName"];
blobService.startCopyBlob(storageuri, containerName, blobName, err => 
if (err) 
console.log(err)
return res.status(500).json(
message: 'error',
status: err
)

..... ..

【问题讨论】:

能否告诉我 sourceContainer 和 desContainer 是否在同一个存储帐户中以及如何创建 sas 令牌? 是的,他们在同一个帐户中。我可以复制文件但对于文件夹,抛出上述错误。 是不是直接把一个文件夹复制到另一个容器里? storageuri='://host/container-name/603487d1e966a91fd86b6c11/spe9_rs_2021-02-23_11-14-41/output/new folder?sv=2019-1........ ....3D' blobname='603487d1e966a91fd86b6c11/spe9_rs_2021-03-17_17-14-38/output/new folder_copy1' 我用的是node js,,blob服务。 【参考方案1】:

Azure Blob 存储具有 2 级层次结构 - Blob 容器和 Blob。它基于平面存储方案,而不是分层方案。它没有目录结构。我们只需在 blob 名称中指定字符或字符串分隔符即可创建虚拟层次结构。所以如果我们想用azure node blob sdk复制一个文件夹,就需要一个一个的复制文件夹中的blob。

例如 sdk

npm i @azure/storage-blob

代码

const 
  BlobServiceClient,
  StorageSharedKeyCredential,
  generateBlobSASQueryParameters,
  ContainerSASPermissions,
 = require("@azure/storage-blob");

const accountName = "andyprivate";
const accountKey =
  "";
const creds = new StorageSharedKeyCredential(accountName, accountKey);
const blobServiceClient = new BlobServiceClient(
  `https://$accountName.blob.core.windows.net`,
  creds
);
async function test() 
  try 
    const sourceContainerClient = blobServiceClient.getContainerClient("input");
    const desContainerClient = blobServiceClient.getContainerClient("output");
    const blobSAS = generateBlobSASQueryParameters(
      
        expiresOn: new Date(new Date().valueOf() + 86400000),
        containerName: sourceContainerClient.containerName,
        permissions: ContainerSASPermissions.parse("rl"),
      ,
      creds
    ).toString();
    for await (const response of sourceContainerClient
      .listBlobsFlat( prefix: "<your folder name>/" )
      .byPage()) 
      for (const blob of response.segment.blobItems) 
        console.log(`Blob name : $blob.name`);
        const sourceBlob = sourceContainerClient.getBlobClient(blob.name);
        const sourceUrl = sourceBlob.url + "?" + blobSAS;
        const res = await (
          await desContainerClient
            .getBlobClient(blob.name)
            .beginCopyFromURL(sourceUrl)
        ).pollUntilDone();

        console.log(res.copyStatus);
      
    
   catch (error) 
    console.log(error);
  

test();

另外,如果你想直接从一个容器复制一个文件夹到另一个容器,我们可以使用 azcopy 实现。更多详情请参考here和here

例如

npm i @azure/storage-blob @azure-tools/azcopy-node @azure-tools/azcopy-<your system win32 linux win64>
 

代码

const 
  StorageSharedKeyCredential,
  generateAccountSASQueryParameters,
  AccountSASPermissions,
  AccountSASResourceTypes,
  AccountSASServices,
 = require("@azure/storage-blob");

const accountName = "andyprivate";
const accountKey =
  "";
const creds = new StorageSharedKeyCredential(accountName, accountKey);
//create account sas token
const accountSas = generateAccountSASQueryParameters(
  
    startsOn: new Date(new Date().valueOf() - 8640),
    expiresOn: new Date(new Date().valueOf() + 86400000),
    resourceTypes: AccountSASResourceTypes.parse("sco").toString(),
    permissions: AccountSASPermissions.parse("rwdlacup").toString(),
    services: AccountSASServices.parse("b").toString(),
  ,
  creds
).toString();
const  AzCopyClient  = require("@azure-tools/azcopy-node");
let copyClient = new AzCopyClient();

async function copy() 


  try 
    let jobId = await copyClient.copy(
      
        type: "RemoteSas",
        resourceUri: "https://<>.blob.core.windows.net/input",
        sasToken: accountSas,
        path: "/<folder name>",
      ,
      
        type: "RemoteSas",
        resourceUri: "https://<>.blob.core.windows.net/outcontainer",
        sasToken: accountSas,
        path: "",
      ,
       recursive: true 
    );
    let status;
    while (!status || status.StatusType !== "EndOfJob") 
      let jobInfo = await copyClient.getJobInfo(jobId);
      status = jobInfo.latestStatus;
      await new Promise((resolve, reject) => setTimeout(resolve, 1000));
    
    console.log("OK");
   catch (error) 
    console.log(error);
  


copy();

【讨论】:

以上是关于如何从 Blob 存储中复制文件夹?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Nodejs 将文件从 Azure 存储 blob(容器)复制到 Azure 文件共享

将文件从 SFTP 复制到 Blob 存储时并行执行 Azure 逻辑应用

如何使用数据工厂将 IoT 中心存储的 blob 复制到 Azure SQL

Azure 函数 Blob 触发器将文件复制到文件共享

如何在 adf 中按顺序进行复制活动?

将文件从AWS S3复制到Azure存储存档层