使用 .NET 针对 Azure 文件进行开发
了解开发使用 Azure 文件存储来存储数据的 .NET 应用程序的基础知识。 本文介绍了如何创建一个简单的控制台应用程序,以便通过 .NET 和 Azure 文件存储执行以下操作:
- 获取文件内容。
- 为文件共享设置最大大小或配额。
- 为文件创建共享访问签名 (SAS)。
- 将文件复制到同一存储帐户中的另一个文件。
- 将文件复制到同一存储帐户中的一个 Blob。
- 创建文件共享的快照。
- 从共享快照还原文件。
- 使用 Azure 存储度量值进行故障排除。
若要了解有关 Azure 文件存储的详细信息,请参阅什么是 Azure 文件存储?
适用于
文件共享类型 | SMB | NFS |
---|---|---|
标准文件共享 (GPv2)、LRS/ZRS | ||
标准文件共享 (GPv2)、GRS/GZRS | ||
高级文件共享 (FileStorage)、LRS/ZRS |
了解 .NET API
Azure 文件为客户端应用程序提供两个主要方法:服务器消息块 (SMB) 和 REST。 在 .NET 中,System.IO
和 Azure.Storage.Files.Shares
API 将抽象化这些方法。
API | 何时使用 | 说明 |
---|---|---|
System.IO | 应用程序:
|
一般情况下,通过 SMB 使用 Azure 文件存储实现的文件 I/O 与使用任何网络文件共享或本地存储设备实现的 I/O 相同。 有关 .NET 中的许多功能(包括文件 I/O)的简介,请参阅控制台应用程序教程。 |
Azure.Storage.Files.Shares | 应用程序:
|
本文演示如何通过 REST(而不是 SMB)将 Azure.Storage.Files.Shares 用于文件 I/O 以及如何管理文件共享。 |
创建控制台应用程序,并获取程序集
可以在任意类型的 .NET 应用中使用 Azure 文件存储客户端库。 这些应用包括 Azure 云应用、Web 应用、桌面应用和移动应用。 为简单起见,我们在本指南中创建一个控制台应用程序。
在 Visual Studio 中创建新的 Windows 控制台应用程序。 以下步骤演示了如何在 Visual Studio 2019 中创建控制台应用程序。 在其他版本的 Visual Studio 中,这些步骤是类似的。
- 启动 Visual Studio 并选择“创建新项目”。
- 在“创建新项目” 中,选择用于 C# 的“控制台应用(.NET Framework)” ,然后选择“下一步” 。
- 在“配置新项目”中输入应用的名称,然后选择“创建”。
将本文中的所有代码示例添加到 Program.cs 文件中的 Program
类。
使用 NuGet 安装所需包
在你的项目中引用以下包:
- 适用于 .NET 的 Azure Core 库:此包是 Azure 客户端管道的实现。
- 适用于 .NET 的 Azure 存储 Blob 客户端库:使用此包能够以编程方式访问存储帐户中的 Blob 资源。
- 适用于 .NET 的 Azure 存储文件客户端库:使用此包能够以编程方式访问存储帐户中的文件资源。
- 适用于 .NET 的系统配置管理器库:此包提供了一个类,用于在配置文件中存储和检索值。
可以使用 NuGet 获取这些包。 执行以下步骤:
在“解决方案资源管理器”中,右键单击你的项目并选择“管理 NuGet 包” 。
在“NuGet 包管理器”中选择“浏览”。 接着搜索并选择“Azure.Core”,然后选择“安装”。
此步骤将安装该包及其依赖项。
搜索并安装以下包:
- Azure.Storage.Blobs
- Azure.Storage.Files.Shares
- System.Configuration.ConfigurationManager
将存储帐户凭据保存到 App.config 文件
接下来,将凭据保存到项目的 App.config 文件中。 在“解决方案资源管理器”中,双击 App.config
并编辑该文件,使其类似于以下示例。
请将 myaccount
替换为你的存储帐户名,将 mykey
替换为你的存储帐户密钥。
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="StorageConnectionString"
value="DefaultEndpointsProtocol=https;AccountName=myaccount;AccountKey=mykey;EndpointSuffix=core.chinacloudapi.cn" />
<add key="StorageAccountName" value="myaccount" />
<add key="StorageAccountKey" value="mykey" />
</appSettings>
</configuration>
注意
Azurite 存储模拟器目前不支持 Azure 文件。 连接字符串必须针对云中要使用 Azure 文件存储的 Azure 存储帐户。
添加 using 指令
在“解决方案资源管理器”中打开 Program.cs 文件,并在该文件顶部添加以下 using 指令。
using System;
using System.Configuration;
using System.IO;
using System.Threading.Tasks;
using Azure;
using Azure.Storage;
using Azure.Storage.Blobs;
using Azure.Storage.Files.Shares;
using Azure.Storage.Files.Shares.Models;
using Azure.Storage.Sas;
以编程方式访问文件共享
在 Program.cs 文件中添加以下代码,以便以编程方式访问文件共享。
如果文件共享尚不存在,则以下方法将创建该文件共享。 该方法首先从连接字符串创建一个 ShareClient 对象。 然后,该示例会尝试下载我们先前创建的文件。 从 Main()
调用此方法。
//-------------------------------------------------
// Create a file share
//-------------------------------------------------
public async Task CreateShareAsync(string shareName)
{
// Get the connection string from app settings
string connectionString = ConfigurationManager.AppSettings["StorageConnectionString"];
// Instantiate a ShareClient which will be used to create and manipulate the file share
ShareClient share = new ShareClient(connectionString, shareName);
// Create the share if it doesn't already exist
await share.CreateIfNotExistsAsync();
// Ensure that the share exists
if (await share.ExistsAsync())
{
Console.WriteLine($"Share created: {share.Name}");
// Get a reference to the sample directory
ShareDirectoryClient directory = share.GetDirectoryClient("CustomLogs");
// Create the directory if it doesn't already exist
await directory.CreateIfNotExistsAsync();
// Ensure that the directory exists
if (await directory.ExistsAsync())
{
// Get a reference to a file object
ShareFileClient file = directory.GetFileClient("Log1.txt");
// Ensure that the file exists
if (await file.ExistsAsync())
{
Console.WriteLine($"File exists: {file.Name}");
// Download the file
ShareFileDownloadInfo download = await file.DownloadAsync();
// Save the data to a local file, overwrite if the file already exists
using (FileStream stream = File.OpenWrite(@"downloadedLog1.txt"))
{
await download.Content.CopyToAsync(stream);
await stream.FlushAsync();
stream.Close();
// Display where the file was saved
Console.WriteLine($"File downloaded: {stream.Name}");
}
}
}
}
else
{
Console.WriteLine($"CreateShareAsync failed");
}
}
设置文件共享的最大大小
从 Azure 文件存储客户端库的 5.x 版开始,可以设置文件共享的配额(最大大小)。 还可以查看共享当前存储了多少数据。
设置共享配额可以限制在该共享上存储的文件的总大小。 如果共享上的文件总大小超出了配额,则客户端无法增大现有文件的大小。 客户端也无法创建新文件,除非这些文件是空的。
下面的示例演示如何检查共享的当前使用情况,以及如何设置共享的配额。
//-------------------------------------------------
// Set the maximum size of a share
//-------------------------------------------------
public async Task SetMaxShareSizeAsync(string shareName, int increaseSizeInGiB)
{
const long ONE_GIBIBYTE = 10737420000; // Number of bytes in 1 gibibyte
// Get the connection string from app settings
string connectionString = ConfigurationManager.AppSettings["StorageConnectionString"];
// Instantiate a ShareClient which will be used to access the file share
ShareClient share = new ShareClient(connectionString, shareName);
// Create the share if it doesn't already exist
await share.CreateIfNotExistsAsync();
// Ensure that the share exists
if (await share.ExistsAsync())
{
// Get and display current share quota
ShareProperties properties = await share.GetPropertiesAsync();
Console.WriteLine($"Current share quota: {properties.QuotaInGB} GiB");
// Get and display current usage stats for the share
ShareStatistics stats = await share.GetStatisticsAsync();
Console.WriteLine($"Current share usage: {stats.ShareUsageInBytes} bytes");
// Convert current usage from bytes into GiB
int currentGiB = (int)(stats.ShareUsageInBytes / ONE_GIBIBYTE);
// This line sets the quota to be the current
// usage of the share plus the increase amount
await share.SetQuotaAsync(currentGiB + increaseSizeInGiB);
// Get the new quota and display it
properties = await share.GetPropertiesAsync();
Console.WriteLine($"New share quota: {properties.QuotaInGB} GiB");
}
}
为文件或文件共享生成共享访问签名
从 Azure 文件存储客户端库的 5.x 版开始,可以为文件共享或单个文件生成共享访问签名 (SAS)。
下面的示例方法返回指定共享中文件上的 SAS。
//-------------------------------------------------
// Create a SAS URI for a file
//-------------------------------------------------
public Uri GetFileSasUri(string shareName, string filePath, DateTime expiration, ShareFileSasPermissions permissions)
{
// Get the account details from app settings
string accountName = ConfigurationManager.AppSettings["StorageAccountName"];
string accountKey = ConfigurationManager.AppSettings["StorageAccountKey"];
ShareSasBuilder fileSAS = new ShareSasBuilder()
{
ShareName = shareName,
FilePath = filePath,
// Specify an Azure file resource
Resource = "f",
// Expires in 24 hours
ExpiresOn = expiration
};
// Set the permissions for the SAS
fileSAS.SetPermissions(permissions);
// Create a SharedKeyCredential that we can use to sign the SAS token
StorageSharedKeyCredential credential = new StorageSharedKeyCredential(accountName, accountKey);
// Build a SAS URI
UriBuilder fileSasUri = new UriBuilder($"https://{accountName}.file.core.chinacloudapi.cn/{fileSAS.ShareName}/{fileSAS.FilePath}");
fileSasUri.Query = fileSAS.ToSasQueryParameters(credential).ToString();
// Return the URI
return fileSasUri.Uri;
}
若要详细了解如何创建和使用共享访问签名,请参阅共享访问签名的工作原理。
复制文件
从 Azure 文件存储客户端库的 5.x 版开始,可以将一个文件复制到另一个文件,将一个文件复制到一个 Blob,或将一个 Blob 复制到一个文件。
还可以使用 AzCopy 将一个文件复制到另一个文件或将一个 Blob 复制到一个文件,反之亦然。 请参阅 AzCopy 入门。
注意
如果要将一个 Blob 复制到一个文件,或将一个文件复制到一个 Blob,必须使用共享访问签名 (SAS) 授予对源对象的访问权限,即使是在同一存储帐户内进行复制。
将一个文件复制到另一个文件
以下示例将一个文件复制到同一共享中的另一个文件。 可以使用共享密钥身份验证执行复制,因为此操作在同一存储帐户内复制文件。
//-------------------------------------------------
// Copy file within a directory
//-------------------------------------------------
public async Task CopyFileAsync(string shareName, string sourceFilePath, string destFilePath)
{
// Get the connection string from app settings
string connectionString = ConfigurationManager.AppSettings["StorageConnectionString"];
// Get a reference to the file we created previously
ShareFileClient sourceFile = new ShareFileClient(connectionString, shareName, sourceFilePath);
// Ensure that the source file exists
if (await sourceFile.ExistsAsync())
{
// Get a reference to the destination file
ShareFileClient destFile = new ShareFileClient(connectionString, shareName, destFilePath);
// Start the copy operation
await destFile.StartCopyAsync(sourceFile.Uri);
if (await destFile.ExistsAsync())
{
Console.WriteLine($"{sourceFile.Uri} copied to {destFile.Uri}");
}
}
}
将文件复制到 Blob
以下示例创建一个文件并将其复制到同一存储帐户中的某个 blob。 该示例为源文件创建一个 SAS,服务在复制操作期间使用该 SAS 授予对源文件的访问权限。
//-------------------------------------------------
// Copy a file from a share to a blob
//-------------------------------------------------
public async Task CopyFileToBlobAsync(string shareName, string sourceFilePath, string containerName, string blobName)
{
// Get a file SAS from the method created ealier
Uri fileSasUri = GetFileSasUri(shareName, sourceFilePath, DateTime.UtcNow.AddHours(24), ShareFileSasPermissions.Read);
// Get a reference to the file we created previously
ShareFileClient sourceFile = new ShareFileClient(fileSasUri);
// Ensure that the source file exists
if (await sourceFile.ExistsAsync())
{
// Get the connection string from app settings
string connectionString = ConfigurationManager.AppSettings["StorageConnectionString"];
// Get a reference to the destination container
BlobContainerClient container = new BlobContainerClient(connectionString, containerName);
// Create the container if it doesn't already exist
await container.CreateIfNotExistsAsync();
BlobClient destBlob = container.GetBlobClient(blobName);
await destBlob.StartCopyFromUriAsync(sourceFile.Uri);
if (await destBlob.ExistsAsync())
{
Console.WriteLine($"File {sourceFile.Name} copied to blob {destBlob.Name}");
}
}
}
可以用相同的方式将一个 Blob 复制到一个文件。 如果源对象是一个 Blob,则创建一个 SAS,以便在复制操作期间授予对该 Blob 的访问权限。
共享快照
从 Azure 文件存储客户端库的 8.5 版开始,可以创建共享快照。 还可以列出或浏览共享快照,以及删除共享快照。 创建后,共享快照是只读的。
创建共享快照
下面的示例创建文件共享快照。
//-------------------------------------------------
// Create a share snapshot
//-------------------------------------------------
public async Task CreateShareSnapshotAsync(string shareName)
{
// Get the connection string from app settings
string connectionString = ConfigurationManager.AppSettings["StorageConnectionString"];
// Instatiate a ShareServiceClient
ShareServiceClient shareServiceClient = new ShareServiceClient(connectionString);
// Instantiate a ShareClient which will be used to access the file share
ShareClient share = shareServiceClient.GetShareClient(shareName);
// Ensure that the share exists
if (await share.ExistsAsync())
{
// Create a snapshot
ShareSnapshotInfo snapshotInfo = await share.CreateSnapshotAsync();
Console.WriteLine($"Snapshot created: {snapshotInfo.Snapshot}");
}
}
列出共享快照
以下示例列出共享上的快照。
//-------------------------------------------------
// List the snapshots on a share
//-------------------------------------------------
public void ListShareSnapshots()
{
// Get the connection string from app settings
string connectionString = ConfigurationManager.AppSettings["StorageConnectionString"];
// Instatiate a ShareServiceClient
ShareServiceClient shareServiceClient = new ShareServiceClient(connectionString);
// Display each share and the snapshots on each share
foreach (ShareItem item in shareServiceClient.GetShares(ShareTraits.All, ShareStates.Snapshots))
{
if (null != item.Snapshot)
{
Console.WriteLine($"Share: {item.Name}\tSnapshot: {item.Snapshot}");
}
}
}
列出共享快照中的文件和目录
以下示例浏览共享快照中的文件和目录。
//-------------------------------------------------
// List the snapshots on a share
//-------------------------------------------------
public void ListSnapshotContents(string shareName, string snapshotTime)
{
// Get the connection string from app settings
string connectionString = ConfigurationManager.AppSettings["StorageConnectionString"];
// Instatiate a ShareServiceClient
ShareServiceClient shareService = new ShareServiceClient(connectionString);
// Get a ShareClient
ShareClient share = shareService.GetShareClient(shareName);
Console.WriteLine($"Share: {share.Name}");
// Get as ShareClient that points to a snapshot
ShareClient snapshot = share.WithSnapshot(snapshotTime);
// Get the root directory in the snapshot share
ShareDirectoryClient rootDir = snapshot.GetRootDirectoryClient();
// Recursively list the directory tree
ListDirTree(rootDir);
}
//-------------------------------------------------
// Recursively list a directory tree
//-------------------------------------------------
public void ListDirTree(ShareDirectoryClient dir)
{
// List the files and directories in the snapshot
foreach (ShareFileItem item in dir.GetFilesAndDirectories())
{
if (item.IsDirectory)
{
Console.WriteLine($"Directory: {item.Name}");
ShareDirectoryClient subDir = dir.GetSubdirectoryClient(item.Name);
ListDirTree(subDir);
}
else
{
Console.WriteLine($"File: {dir.Name}\\{item.Name}");
}
}
}
从共享快照还原文件共享或文件
创建文件共享的快照即可恢复各个文件或整个文件共享。
查询文件共享的共享快照即可从文件共享快照还原文件。 然后,可以检索属于特定共享快照的文件。 使用该版本直接读取或还原文件。
//-------------------------------------------------
// Restore file from snapshot
//-------------------------------------------------
public async Task RestoreFileFromSnapshot(string shareName, string directoryName, string fileName, string snapshotTime)
{
// Get the connection string from app settings
string connectionString = ConfigurationManager.AppSettings["StorageConnectionString"];
// Instatiate a ShareServiceClient
ShareServiceClient shareService = new ShareServiceClient(connectionString);
// Get a ShareClient
ShareClient share = shareService.GetShareClient(shareName);
// Get as ShareClient that points to a snapshot
ShareClient snapshot = share.WithSnapshot(snapshotTime);
// Get a ShareDirectoryClient, then a ShareFileClient to the snapshot file
ShareDirectoryClient snapshotDir = snapshot.GetDirectoryClient(directoryName);
ShareFileClient snapshotFile = snapshotDir.GetFileClient(fileName);
// Get a ShareDirectoryClient, then a ShareFileClient to the live file
ShareDirectoryClient liveDir = share.GetDirectoryClient(directoryName);
ShareFileClient liveFile = liveDir.GetFileClient(fileName);
// Restore the file from the snapshot
ShareFileCopyInfo copyInfo = await liveFile.StartCopyAsync(snapshotFile.Uri);
// Display the status of the operation
Console.WriteLine($"Restore status: {copyInfo.CopyStatus}");
}
删除共享快照
下面的示例删除文件共享快照。
//-------------------------------------------------
// Delete a snapshot
//-------------------------------------------------
public async Task DeleteSnapshotAsync(string shareName, string snapshotTime)
{
// Get the connection string from app settings
string connectionString = ConfigurationManager.AppSettings["StorageConnectionString"];
// Instatiate a ShareServiceClient
ShareServiceClient shareService = new ShareServiceClient(connectionString);
// Get a ShareClient
ShareClient share = shareService.GetShareClient(shareName);
// Get a ShareClient that points to a snapshot
ShareClient snapshotShare = share.WithSnapshot(snapshotTime);
try
{
// Delete the snapshot
await snapshotShare.DeleteIfExistsAsync();
}
catch (RequestFailedException ex)
{
Console.WriteLine($"Exception: {ex.Message}");
Console.WriteLine($"Error code: {ex.Status}\t{ex.ErrorCode}");
}
}
使用指标排查 Azure 文件存储问题
Azure 存储分析支持用于 Azure 文件存储的指标。 使用指标数据,可以跟踪请求和诊断问题。
可以通过 Azure 门户为 Azure 文件存储启用指标。 还可以通过 REST API 或 Azure 文件存储客户端库中的类似功能之一调用设置文件服务属性操作,以编程方式启用指标。
以下代码示例演示了如何使用 .NET 客户端库启用 Azure 文件存储的指标。
//-------------------------------------------------
// Use metrics
//-------------------------------------------------
public async Task UseMetricsAsync()
{
// Get the connection string from app settings
string connectionString = ConfigurationManager.AppSettings["StorageConnectionString"];
// Instatiate a ShareServiceClient
ShareServiceClient shareService = new ShareServiceClient(connectionString);
// Set metrics properties for File service
await shareService.SetPropertiesAsync(new ShareServiceProperties()
{
// Set hour metrics
HourMetrics = new ShareMetrics()
{
Enabled = true,
IncludeApis = true,
Version = "1.0",
RetentionPolicy = new ShareRetentionPolicy()
{
Enabled = true,
Days = 14
}
},
// Set minute metrics
MinuteMetrics = new ShareMetrics()
{
Enabled = true,
IncludeApis = true,
Version = "1.0",
RetentionPolicy = new ShareRetentionPolicy()
{
Enabled = true,
Days = 7
}
}
});
// Read the metrics properties we just set
ShareServiceProperties serviceProperties = await shareService.GetPropertiesAsync();
// Display the properties
Console.WriteLine();
Console.WriteLine($"HourMetrics.InludeApis: {serviceProperties.HourMetrics.IncludeApis}");
Console.WriteLine($"HourMetrics.RetentionPolicy.Days: {serviceProperties.HourMetrics.RetentionPolicy.Days}");
Console.WriteLine($"HourMetrics.Version: {serviceProperties.HourMetrics.Version}");
Console.WriteLine();
Console.WriteLine($"MinuteMetrics.InludeApis: {serviceProperties.MinuteMetrics.IncludeApis}");
Console.WriteLine($"MinuteMetrics.RetentionPolicy.Days: {serviceProperties.MinuteMetrics.RetentionPolicy.Days}");
Console.WriteLine($"MinuteMetrics.Version: {serviceProperties.MinuteMetrics.Version}");
Console.WriteLine();
}
如果遇到任何问题,请参阅排查 Azure 文件存储问题。
后续步骤
有关 Azure 文件存储的详细信息,请参阅以下资源:
有关使用已弃用的 .NET 版本 11.x SDK 的相关代码示例,请参阅使用 .NET 版本 11.x 的代码示例。