【问题标题】:How to get blob name from BlobResult[]?如何从 BlobResult[] 中获取 blob 名称?
【发布时间】:2019-11-21 19:34:01
【问题描述】:

我想删除我的 azure blob 存储中的所有文件。为此,我使用 listBlobsSegmented() 列出存储中的所有 blob,然后将结果传递给 deleteBlobIfExists()。但是 list BlobsSegment() 中的参数 blob.name 未正确分配。如何正确获取 blob 名称?

这是存储模型:

const blobService = azure.createBlobService(accountName, accessKey, host); 
const containerName = 'container';

module.exports.listAll = () => {
    return new Promise(function(resolve, reject) {
        blobService.listBlobsSegmented(containerName, null, function(err, listBlobsResult) {
            if (err) {
                reject(err);
            } else {
                resolve(listBlobsResult);
            }
        });
    });
}

module.exports.delete = (blobName) => {
    return new Promise(function(resolve, reject) {
        blobService.deleteBlobIfExists(containerName, blobName, function(err, result) {
            if (err) {
                reject(err);
            } else {
                resolve({ message: `Block blob '${blobName}' deleted` });
            }
        })
    })
}

这就是我使用它们的方式:

const azureStorage = require('./storage-model')

router.get('/listAll', function(req, res) {
    azureStorage.listAll().then((listBlobsResult) => {
        console.log(listBlobsResult);
        res.send(listBlobsResult);
    }).catch((err) => {
        console.log(err);
    });
});

router.get('/deleteAll', function(req, res) {
    azureStorage.listAll().then((listBlobsResult) => {
        var responseBody;
        for (blob in listBlobsResult.entries) {
            azureStorage.delete(blob.name).then((result) => {
                console.log(result);
                responseBody += result;
            }).catch((err) => {
                console.log(err);
            });
        }
        res.send(responseBody);
    }).catch((err) => {
        console.log(err);
    });
})

这样做之后,它给了我错误消息

ArgumentNullError:函数的必需参数 blob 未定义 deleteBlobIfExists

以下是来自 Microsoft 的一些参考资料 deleteBlobIfExists() listBlobsSegmented() ListBlobsResult BlobResult

我发现 blob.name 只返回 blob 索引号,而不是实际的 blob 名称。有没有人可以帮助我?谢谢!


这就是 listBlobsResult.entries 的样子:

[ {previous blob result},
 BlobResult {
    name: 'my_container/some_picture.jpg',
    creationTime: 'Thu, 11 Jul 2019 09:33:20 GMT',
    lastModified: 'Thu, 11 Jul 2019 09:33:20 GMT',
    etag: '0x8D705A4CFCB5528',
    contentLength: '6300930',
    contentSettings:
     { contentType: 'application/octet-stream',
       contentEncoding: '',
       contentLanguage: '',
       contentMD5: 'OyHfg8c3irniQzyhtCBdrw==',
       cacheControl: '',
       contentDisposition: '' },
    blobType: 'BlockBlob',
    lease: { status: 'unlocked', state: 'available' },
    serverEncrypted: 'true' },
 {next blob result},
 ...{many others blob result}]

我期望的是,我可以使用 blob.name 在 listBlobsResult.entries 的迭代中从条目 blob 中获取 blob 名称。但它给了我迭代索引。

【问题讨论】:

  • 如果要删除所有 blob,为什么不直接删除 blob 容器?
  • 你试过listBlobs()而不是listBlobsSegmented()吗?
  • @GauravMantri Beacuase 我想保留容器。但也许先删除容器而不是使用 createContainerIfNotExists() 将是一个很好的备份计划,谢谢!
  • @Neverever 我确保来自 listBlobs()listBlobsSegmented() 的 listBlobsResult 都是正确的。稍后我将编辑问题以公开 listBlobsResult。顺便说一句,listBlobs() 似乎只在较旧的 SDK 中实现,而不是较新的 SDK,我正在使用新的。

标签: javascript node.js azure blob azure-storage


【解决方案1】:

listBlobsResult.entries 的类型为 BlobResult[]

而且,for 循环有两种类型,人们将它们混为一谈是很常见的。

为了……在

for (let index in listBlobsResult.entries) {
    let blob = listBlobsResult.entries[index];

    /* ... do the work */
}

对于...的

for (let blob of listBlobsResult.entries) {
    /* ... do the work */
}

【讨论】:

    【解决方案2】:

    您的代码中有两个问题。

    1. router.get('/deleteAll', callback) 回调函数中的 for...in 语句。根据MDN文档for...in statementfor (blob in listBlobsResult.entries)blob变量实际上就是你说的数组listBlobsResult.entries的数字索引,请看下图。

      所以要修复它,有两种解决方案。

      1.1。要使用for...of statement而不是for...in statement,只需将关键字in更改为of而不做其他更改,那么blob变量就是BlobResult对象。

      for (var blob of listBlobsResult.entries) {
          azureStorage.delete(blob.name).then((result) => {
              console.log(result);
              responseBody += result;
          }).catch((err) => {
              console.log(err);
          });
      }
      

      1.2。要将map 函数用于Array 对象,如下图来自Array object 的MDN 文档。

      listBlobsResult.entries.map((blob) => {
          azureStorage.delete(blob.name).then((result) => {
              console.log(result);
              responseBody += result;
          }).catch((err) => {
              console.log(err);
          });
       });
      
    2. 根据Azure官方文档How to upload, download, and list blobs using the client library for Node.js v2List the blobs小节,如下图,你的listAll函数使用listBlobsSegmented(string, ContinuationToken, ErrorOrResult<ListBlobsResult>)只是通过将null作为@987654353来列出容器中的前5000个blob @参数值,不列出所有的blob。

      因此,如果容器中有超过 5000 个 blob,则要列出所有 blob,首先传递 null 以获取前 5000 个 blob 和 listBlobsResult.continuationToken,然后将前一个 listBlobsResult.continuationToken 值传递给函数 listBlobsSegmented获取接下来的 5000 个 blob,直到 listBlobsResult.continuationToken 值为 null。


    更新:listAll

    的实现
    const listBlobs = async (continuationToken) => {
        return new Promise((resolve, reject) => {
            blobService.listBlobsSegmented(containerName, continuationToken, (err, data) => {
                if (err) {
                    reject(err);
                } else {
                    resolve(data)
                }
            });
        });
    };
    
    const listAll = async () => {
        first = await listBlobs(null);
        all = [].concat(first.entries)
        var continuationToken = first.continuationToken;
        while(continuationToken != null) {
            next = await listBlobs(continuationToken);
            all = all.concat(next.entries)
            continuationToken = next.continuationToken
        }
        return Promise.resolve(all);
    };
    
    (async() => {
        blobs = await listAll();
        blobs.map((result, index) => {console.log(index, result.name)})
    })();
    

    【讨论】:

    • 感谢详细解答!我会尽快解决 listBlobsSegmented() 问题。
    • @yyp 我发布了listAll 的实现。
    【解决方案3】:

    列出 blob 时有一个名为 delimiter 的选项。示例代码:

    blobService.listBlobsSegmentedWithPrefix('documents',null,null,{delimiter:'/'},(error,result,response)=>{
        console.log(result);
        console.log(response.body.EnumerationResults.Blobs.BlobPrefix);
    })
    

    使用分隔符/,列出操作返回两部分的结果。

    • result,包含容器根目录下的blob信息,例如文件名
    • 响应正文中的 BlobPrefix,包含带分隔符的单级目录名称。

    [ { Name: 'docx/' }, { Name: 'xlsx/' } ]

    希望对你有帮助。

    【讨论】:

    • 我也试过这个解决方案。这是一种非常实用的方法,让我学到了更多东西,但并没有直接解决我的问题。感谢您的回答!
    猜你喜欢
    • 2022-11-09
    • 2021-02-03
    • 1970-01-01
    • 1970-01-01
    • 2020-06-13
    • 1970-01-01
    • 2014-09-26
    • 2017-10-14
    • 2021-12-14
    相关资源
    最近更新 更多