node.js - 使用nodejs和blob服务从blob存储下载子目录/目录?
问题描述
我已经使用 blob 服务的 getBlobProperties() 和 createReadStream(containerName, fullPath, options) 方法实现了下载文件。现在,我正在尝试使用相同的方法在我的容器中下载目录/子目录,但它不起作用,并且抛出错误,指定的 blob 不存在。尽管我知道此错误的原因,但由于我不想循环 blob 并分别下载每个文件,我该如何克服这个问题?我想下载一个完整的文件夹。
这是API:
exports.getBlobChunk = function (req, res) {
var userrole = utils.sanitizeStr(req.body.userrole);
var srcFilePath = utils.sanitizeStr(req.body.srcfilePath);
var fileName = utils.sanitizeStr(req.body.srcfileName);
var fullPath = srcFilePath + "/" + fileName;
var startRange = req.headers['startrange'];
var endRange = req.headers['endrange'];
genericHandler.getUserSubscMapping().then(function (results) {
if (results != undefined && results != null) {
var item = results[0].mapping.find(item => item.name == userrole);
var sasurl = item.sasurl;
if (sasurl == null) {
res.status(500).send("Subscription mapping not configured");
return;
}
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 download = item.download; // download usage
var blobService = storage.createBlobServiceWithSas(host, saskey);
blobService.getBlobProperties(containerName, fullPath, function (err, properties, status) {
if (err) {
res.send(502, "Error fetching file: %s", err.message);
} else if (!status.isSuccessful) {
res.send(404, "The file %s does not exist", fullPath);
} else {
var contentLength = properties.contentLength / 1024; // bytes to KB
res.header('Content-Type', "application/zip");
res.attachment(fileName);
var options = {
rangeStart: startRange,
rangeEnd: endRange
};
if (startRange == 0) { // update download size on first chunk
exports.updateStorageDownload(userrole, contentLength, download);
}
blobService.createReadStream(containerName, fullPath, options).pipe(res);
}
});
}
解决方案
Azure Blob 存储没有文件夹的概念,容器内的所有内容都被视为一个 Blob,包括文件夹。因此,您无法下载具有文件夹名称的目录/子目录。
例如:
集装箱结构
hello.txt ... test test.txt test1 data.json
您需要从目录中一一下载 blob 文件。
const {
BlobServiceClient,
StorageSharedKeyCredential,
} = require("@azure/storage-blob");
// Enter your storage account name and shared key
const account = "";
const accountKey ="";
const containerName = "";
const filePath = "D:/downloads/"
// Use StorageSharedKeyCredential with storage account and account key
// StorageSharedKeyCredential is only available in Node.js runtime, not in browsers
const sharedKeyCredential = new StorageSharedKeyCredential(account, accountKey);
const blobServiceClient = new BlobServiceClient(
`https://${account}.blob.core.windows.net`,
sharedKeyCredential,
);
async function listBlobs() {
const containerClient = await blobServiceClient.getContainerClient(containerName);
console.log("list blobs with method listBlobsFlat");
let iter = containerClient.listBlobsFlat({ prefix: "test/" });
for await (const item of iter) {
console.log(`\tBlobItem: name - ${item.name}`);
downloadBlobToLocal(containerClient, item.name, filePath);
}
console.log("list blobs with method listBlobsByHierarchy");
let iter1 = containerClient.listBlobsByHierarchy("/", { prefix: "test/" });
for await (const item of iter1) {
if (item.kind === "prefix") {
console.log(`\tBlobPrefix: ${item.name}`);
await listblob(containerClient, item.name);
} else {
console.log(`\tBlobItem: name - ${item.name}`);
downloadBlobToLocal(containerClient, item.name, filePath);
}
}
}
async function listblob(containerClient, prefix) {
let iter1 = containerClient.listBlobsByHierarchy("/", { prefix: prefix });
for await (const item of iter1) {
if (item.kind === "prefix") {
console.log(`\tBlobPrefix: ${item.name}`);
} else {
console.log(`\tBlobItem: name - ${item.name}`);
downloadBlobToLocal(containerClient, item.name, filePath);
}
}
}
async function downloadBlobToLocal(containerClient, blobName, filePath) {
const blockBlobClient = containerClient.getBlockBlobClient(blobName);
const downloadBlockBlobResponse = await blockBlobClient.downloadToFile(filePath + blobName);
}
listBlobs().catch((err) => {
console.error("Error running sample:", err.message);
});
推荐阅读
- rabbitmq - 有时 RabbitMQ 集群开始冻结并运行缓慢
- javascript - 在 JavaScript 中同时使用 Babel 和 Razor?
- amazon-ec2 - Lambda 函数访问同一安全组中的 EC2 实例
- python - 如何通过单击 QPushButton 打印 QTableWidget
- kubernetes - 我可以更详细地查看推出吗?
- python - 在引用列时将函数逐行应用于熊猫数据框
- javascript - 如何从客户端的图像中删除 EXIF?(JS 或 Angular)
- spring-boot - Springboot/Spring Batch 加载不带分隔符的文件
- flutter - 拉动刷新WebView
- python - 使用 Python 从 csv 文件自动创建 BigQuery 架构/表