如何使用适用于 Node.js v2 的客户端库上传、下载和列出 BlobHow to upload, download, and list blobs using the client library for Node.js v2

本操作指南介绍如何使用适用于 Node.js v2 的客户端库通过 Azure Blob 存储来上传、下载和列出 Blob。In this how-to guide, you learn how to use the client library for Node.js v2 to upload, download, and list blobs with Azure Blob storage.

Tip

适用于 Node.js 的 Azure 存储客户端库的最新版本是 v10。The latest version of the Azure Storage client library for Node.js is v10. 我们建议尽可能使用最新版本的客户端库。We recommend that you use the latest version of the client library when possible. 若要开始使用 v10,请参阅快速入门:使用适用于 JavaScript v10 的 Azure 存储客户端库上传、下载、列出和删除 Blob(预览版)To get started using v10, see Quickstart: Upload, download, list, and delete blobs using Azure Storage client library for JavaScript v10 (preview).

先决条件Prerequisites

如果没有 Azure 订阅,可在开始前创建一个 1 元人民币试用帐户If you don't have an Azure subscription, create a 1rmb trial account before you begin.

Azure 门户中创建 Azure 存储帐户。Create an Azure storage account in the Azure portal. 有关如何创建帐户的帮助,请参阅创建存储帐户For help creating the account, see Create a storage account.

下载示例应用程序Download the sample application

示例应用程序是简单的 Node.js 控制台应用程序。The sample application is a simple Node.js console application. 若要开始,请使用以下命令将存储库克隆到计算机:To begin, clone the repository to your machine using the following command:

git clone https://github.com/Azure-Samples/storage-blobs-node-quickstart.git

若要打开应用程序,请找到 storage-blobs-node-quickstart 文件夹,然后在最常用的代码编辑环境中将其打开。To open the application, look for the storage-blobs-node-quickstart folder and open it in your favorite code editing environment.

从 Azure 门户复制凭据Copy your credentials from the Azure portal

此示例应用程序需对存储帐户访问进行身份验证。The sample application needs to authenticate access to your storage account. 若要进行身份验证,请将存储帐户凭据以连接字符串形式添加到应用程序中。To authenticate, add your storage account credentials to the application as a connection string. 按照以下步骤查看存储帐户凭据:View your storage account credentials by following these steps:

  1. 导航到 Azure 门户Navigate to the Azure portal.

  2. 找到自己的存储帐户。Locate your storage account.

  3. 在存储帐户概述的“设置”部分,选择“访问密钥”。In the Settings section of the storage account overview, select Access keys. 在这里,可以查看你的帐户访问密钥以及每个密钥的完整连接字符串。Here, you can view your account access keys and the complete connection string for each key.

  4. 找到“密钥 1”下面的“连接字符串”值,选择“复制”按钮复制该连接字符串。Find the Connection string value under key1, and select the Copy button to copy the connection string. 下一步需将此连接字符串值添加到某个环境变量。You will add the connection string value to an environment variable in the next step.

    显示如何从 Azure 门户复制连接字符串的屏幕截图

配置存储连接字符串Configure your storage connection string

在运行应用程序之前,必须为存储帐户提供连接字符串。Before running the application, you must provide the connection string for your storage account. 示例存储库包括名为 .env.example 的文件。The sample repository includes a file named .env.example. 可以通过删除 .example 扩展来重命名此文件,这样会生成名为 .env 的文件。You can rename this file by removing the .example extension, which results in a file named .env. .env 文件中,请将连接字符串值添加到 AZURE_STORAGE_CONNECTION_STRING 键之后。Inside the .env file, add your connection string value after the AZURE_STORAGE_CONNECTION_STRING key.

安装所需程序包Install required packages

在应用程序目录中运行 npm install,以安装应用程序所需的包。In the application directory, run npm install to install the required packages for the application.

npm install

运行示例Run the sample

安装依赖项以后,即可发出以下命令,以便运行示例:Now that the dependencies are installed, you can run the sample by issuing the following command:

npm start

此脚本的输出将类似于以下内容:The output from the script will be similar to the following:

Containers:
 - container-one
 - container-two
Container "demo" is created
Blob "quickstart.txt" is uploaded
Local file "./readme.md" is uploaded
Blobs in "demo" container:
 - quickstart.txt
 - readme.md
Blob downloaded blob content: "hello Blob SDK"
Blob "quickstart.txt" is deleted
Container "demo" is deleted
Done

如果为此示例使用新的存储帐户,则可能无法看到“Containers”标签下列出的任何容器名称。If you are using a new storage account for this example, then you may not see any container names listed under the label "Containers".

了解代码Understanding the code

第一个表达式用于将值加载到环境变量中。The first expression is used to load values into environment variables.

if (process.env.NODE_ENV !== 'production') {
    require('dotenv').load();
}

在本地运行应用以进行调试时,dotenv 模块会加载环境变量。The dotenv module loads environment variables when running the app locally for debugging. 值在名为 .env 的文件中定义,并加载到当前执行上下文中。Values are defined in a file named .env and loaded into the current execution context. 在生产上下文中,服务器配置会提供这些值,这就是为什么此代码仅当脚本不在“生产”上下文下运行时才运行的原因。In production contexts, the server configuration provides these values and that is why this code is only run when the script is not running under a "production" context.

const path = require('path');
const storage = require('azure-storage');

模块的用途如下:The purpose of the modules is as follows:

将名为 .env 的文件加载到当前执行上下文中file named .env into the current execution context

  • 若要确定要上传到 Blob 存储的文件的绝对路径,path 是必需的path is required in order to determine the absolute file path of the file to upload to blob storage
  • azure-storage 是适用于 Node.js 的 Azure 存储客户端库模块azure-storage is the Azure Storage client library module for Node.js

接下来,将 blobService 变量初始化为 Azure Blob 服务的新实例。Next, the blobService variable is initialized as a new instance of the Azure Blob service.

const blobService = storage.createBlobService();

在以下实现中,每个 blobService 函数都包装在 Promise 中,因此可以访问 JavaScript 的 async 函数和 await 运算符,以便简化 Azure 存储 API 的回调性质。In the following implementation, each of the blobService functions is wrapped in a Promise, which allows access to JavaScript's async function and await operator to streamline the callback nature of the Azure Storage API. 针对每个函数返回成功的响应后,promise 会使用相关的数据和特定于操作的消息进行解析。When a successful response returns for each function, the promise resolves with relevant data along with a message specific to the action.

列出容器List containers

listContainers 函数调用 listContainersSegmented,后者返回组中容器的集合。The listContainers function calls listContainersSegmented which returns collections of containers in groups.

const listContainers = async () => {
    return new Promise((resolve, reject) => {
        blobService.listContainersSegmented(null, (err, data) => {
            if (err) {
                reject(err);
            } else {
                resolve({ message: `${data.entries.length} containers`, containers: data.entries });
            }
        });
    });
};

组的大小可以通过 ListContainersOptions 进行配置。The size of the groups is configurable via ListContainersOptions. 调用 listContainersSegmented 会返回 ContainerResult 实例数组形式的 Blob 元数据。Calling listContainersSegmented returns blob metadata as an array of ContainerResult instances. 结果以 5,000 增量批次(段)的方式返回。Results are returned in 5,000 increment batches (segments). 如果容器中有 5,000 个以上的 Blob,则结果中会包含一个 continuationToken 值。If there are more than 5,000 blobs in a container, then the results include a value for continuationToken. 若要列出 Blob 容器中的后续段,可以将继续标记作为第二个参数传递回 listContainersSegment 中。To list subsequent segments from the blob container, you can pass the continuation token back into listContainersSegment as the second argument.

创建容器Create a container

createContainer 函数调用 createContainerIfNotExists 并为 Blob 设置相应的访问级别。The createContainer function calls createContainerIfNotExists and sets the appropriate access level for the blob.

const createContainer = async (containerName) => {
    return new Promise((resolve, reject) => {
        blobService.createContainerIfNotExists(containerName, { publicAccessLevel: 'blob' }, err => {
            if (err) {
                reject(err);
            } else {
                resolve({ message: `Container '${containerName}' created` });
            }
        });
    });
};

createContainerIfNotExists 的第二个参数(选项)接受一个值作为 publicAccessLevelThe second parameter (options) for createContainerIfNotExists accepts a value for publicAccessLevel. 如果 publicAccessLevel 的值为 blob,则表示会公开特定的 Blob 数据。The value blob for publicAccessLevel specifies that specific blob data is exposed to the public. 此设置不同于容器级别的访问权限,后者授予列出容器内容的权限。This setting is in contrast to container level access, which grants the ability to list the contents of the container.

使用 createContainerIfNotExists 时,应用程序可以多次运行 createContainer 命令,在容器存在的情况下也不会返回错误。The use of createContainerIfNotExists allows the application to run the createContainer command multiple times without returning errors when the container already exists. 在生产环境中,通常只调用 createContainerIfNotExists 一次,因为在应用程序中,从头至尾使用的是同一容器。In a production environment, you often only call createContainerIfNotExists once as the same container is used throughout the application. 在这种情况下,可以通过门户或 Azure CLI 提前创建容器。In these cases, you can create the container ahead of time through the portal or via the Azure CLI.

上传文本Upload text

uploadString 函数调用 createBlockBlobFromText,以便将任意字符串写入(或覆盖)到 Blob 容器。The uploadString function calls createBlockBlobFromText to write (or overwrite) an arbitrary string to the blob container.

const uploadString = async (containerName, blobName, text) => {
    return new Promise((resolve, reject) => {
        blobService.createBlockBlobFromText(containerName, blobName, text, err => {
            if (err) {
                reject(err);
            } else {
                resolve({ message: `Text "${text}" is written to blob storage` });
            }
        });
    });
};

上传本地文件Upload a local file

uploadLocalFile 函数通过 createBlockBlobFromLocalFile 将文件从文件系统上传和写入(或覆盖)到 Blob 存储中。The uploadLocalFile function uses createBlockBlobFromLocalFile to upload and write (or overwrite) a file from the file system into blob storage.

const uploadLocalFile = async (containerName, filePath) => {
    return new Promise((resolve, reject) => {
        const fullPath = path.resolve(filePath);
        const blobName = path.basename(filePath);
        blobService.createBlockBlobFromLocalFile(containerName, blobName, fullPath, err => {
            if (err) {
                reject(err);
            } else {
                resolve({ message: `Local file "${filePath}" is uploaded` });
            }
        });
    });
};

其他适用于将内容上传到 Blob 中的方法涉及到使用文本Other approaches available to upload content into blobs include working with text and streams. 为了验证文件是否已上传到 Blob 存储,可以使用 Azure 存储资源管理器查看帐户中的数据。To verify the file is uploaded to your blob storage, you can use the Azure Storage Explorer to view the data in your account.

列出 BlobList the blobs

listBlobs 函数在调用 listBlobsSegmented 方法后会返回一个列表,其中包含容器中的 Blob 元数据。The listBlobs function calls the listBlobsSegmented method to return a list of blob metadata in a container.

const listBlobs = async (containerName) => {
    return new Promise((resolve, reject) => {
        blobService.listBlobsSegmented(containerName, null, (err, data) => {
            if (err) {
                reject(err);
            } else {
                resolve({ message: `${data.entries.length} blobs in '${containerName}'`, blobs: data.entries });
            }
        });
    });
};

调用 listBlobsSegmented 会返回 BlobResult 实例数组形式的 Blob 元数据。Calling listBlobsSegmented returns blob metadata as an array of BlobResult instances. 结果以 5,000 增量批次(段)的方式返回。Results are returned in 5,000 increment batches (segments). 如果容器中有 5,000 个以上的 Blob,则结果中会包含一个 continuationToken 值。If there are more than 5,000 blobs in a container, then the results include a value for continuationToken. 若要列出 Blob 容器中的后续段,可以将继续标记作为第二个参数传递回 listBlobSegmented 中。To list subsequent segments from the blob container, you can pass the continuation token back into listBlobSegmented as the second argument.

下载 BlobDownload a blob

downloadBlob 函数使用 getBlobToText 将 Blob 的内容下载到给定的绝对文件路径。The downloadBlob function uses getBlobToText to download the contents of the blob to the given absolute file path.

const downloadBlob = async (containerName, blobName) => {
    const dowloadFilePath = path.resolve('./' + blobName.replace('.txt', '.downloaded.txt'));
    return new Promise((resolve, reject) => {
        blobService.getBlobToText(containerName, blobName, (err, data) => {
            if (err) {
                reject(err);
            } else {
                resolve({ message: `Blob downloaded "${data}"`, text: data });
            }
        });
    });
};

此处显示的实现更改了源并将 Blob 的内容作为字符串返回。The implementation shown here changes the source returns the contents of the blob as a string. 也可将 Blob 作为来下载,或者直接下载到本地文件You can also download the blob as a stream as well as directly to a local file.

删除 BlobDelete a blob

deleteBlob 函数调用 deleteBlobIfExists 函数。The deleteBlob function calls the deleteBlobIfExists function. 顾名思义,如果 Blob 已删除,此函数不返回错误。As the name implies, this function does not return an error if the blob is already deleted.

const deleteBlob = async (containerName, blobName) => {
    return new Promise((resolve, reject) => {
        blobService.deleteBlobIfExists(containerName, blobName, err => {
            if (err) {
                reject(err);
            } else {
                resolve({ message: `Block blob '${blobName}' deleted` });
            }
        });
    });
};

删除容器Delete a container

可以通过对 Blob 服务调用 deleteContainer 方法并传入容器名称来删除容器。Containers are deleted by calling the deleteContainer method off the blob service and passing in the container name.

const deleteContainer = async (containerName) => {
    return new Promise((resolve, reject) => {
        blobService.deleteContainer(containerName, err => {
            if (err) {
                reject(err);
            } else {
                resolve({ message: `Container '${containerName}' deleted` });
            }
        });
    });
};

调用代码Calling code

为了支持 JavaScript 的 async/await 语法,所有调用代码都包装在一个名为 execute 的函数中。In order to support JavaScript's async/await syntax, all the calling code is wrapped in a function named execute. 然后按约定调用并处理 execute。Then execute is called and handled as a promise.

async function execute() {
    // commands 
}

execute().then(() => console.log("Done")).catch((e) => console.log(e));

以下所有代码都在 execute 函数内 // commands 注释所在的位置处运行。All of the following code runs inside the execute function where the // commands comment is placed.

首先,声明相关变量以分配名称、示例内容并指向要上传到 Blob 存储的本地文件。First, the relevant variables are declared to assign names, sample content and to point to the local file to upload to Blob storage.

const containerName = "demo";
const blobName = "quickstart.txt";
const content = "hello Node SDK";
const localFilePath = "./readme.md";
let response;

若要列出存储帐户中的容器,请调用 listContainers 函数,然后返回的容器列表会记录到输出窗口。To list the containers in the storage account, the listContainers function is called and the returned list of containers is logged to the output window.

console.log("Containers:");
response = await listContainers();
response.containers.forEach((container) => console.log(` -  ${container.name}`));

容器列表可用以后,即可使用数组的 findIndex 方法来查看要创建的容器是否已存在。Once the list of containers is available, then you can use the Array findIndex method to see if the container you want to create already exists. 如果该容器不存在,则会创建它。If the container does not exist then the container is created.

const containerDoesNotExist = response.containers.findIndex((container) => container.name === containerName) === -1;

if (containerDoesNotExist) {
    await createContainer(containerName);
    console.log(`Container "${containerName}" is created`);
}

接下来,将字符串和本地文件上传到 Blob 存储。Next, a string and a local file is uploaded to Blob storage.

await uploadString(containerName, blobName, content);
console.log(`Blob "${blobName}" is uploaded`);

response = await uploadLocalFile(containerName, localFilePath);
console.log(response.message);

列出 Blob 的过程与列出容器的过程相同。The process to list blobs is the same as listing containers. 调用 listBlobs 会返回容器中 Blob 的数组,这些 Blob 会记录到输出窗口中。The call to listBlobs returns an array of blobs in the container and are logged to the output window.

console.log(`Blobs in "${containerName}" container:`);
response = await listBlobs(containerName);
response.blobs.forEach((blob) => console.log(` - ${blob.name}`));

若要下载某个 Blob,请捕获响应并用其来访问 Blob 的值。To download a blob, the response is captured and used to access the value of the blob. 在响应中,readableStreamBody 会转换为字符串并记录到输出窗口。From the response readableStreamBody is converted to a string and logged out to the output window.

response = await downloadBlob(containerName, blobName);
console.log(`Downloaded blob content: "${response.text}"`);

最终,Blob 和容器会从存储帐户中删除。Finally, the blob and container are deleted from the storage account.

await deleteBlob(containerName, blobName);
console.log(`Blob "${blobName}" is deleted`);

await deleteContainer(containerName);
console.log(`Container "${containerName}" is deleted`);

清理资源Clean up resources

写入存储帐户的所有数据都会在代码示例结束时自动删除。All data written to the storage account is automatically deleted at the end of the code sample.

用于通过 Blob 开发 Node.js 应用程序的资源Resources for developing Node.js applications with blobs

请查看以下其他资源,了解如何通过 Blob 存储进行 Node.js 开发:See these additional resources for Node.js development with Blob storage:

二进制文件和源代码Binaries and source code

客户端库参考和示例Client library reference and samples

后续步骤Next steps

本文介绍了如何使用 Node.js 在本地磁盘和 Azure Blob 存储之间上传文件。This article demonstrates how to upload a file between a local disk and Azure Blob storage using Node.js. 若要深入了解如何使用 Blob 存储,请转到 GitHub 存储库。To learn more about working with Blob storage, continue to the GitHub repository.