解压缩文件并将它们保存到 Blob 存储流
Unzip files and save them to a Blob Storage stream
这个概念验证的工作流程是:
- Azure Function App 在 blob 存储中检测到 .zip 文件 (
Stream inputBlob
)
- 函数应用程序调用我的代码,它需要提取文件并将它们单独保存到 Blob 存储容器
Stream outputBlob
代码确实从 inputBlob
获取了 .zip,我可以在调试器中看到 ZipArchive
包含 .zip 的内容。但是没有文件输出,没有错误。我需要做什么才能将所有文件保存到 outputBlob
流?我确定我遗漏了与流复制相关的内容。
[FunctionName("Name")]
public static void Run(
[BlobTrigger("input/{name}", Connection = "AzureWebJobsStorage")]Stream inputBlob,
[Blob("output/{name}", FileAccess.Write)] Stream outputBlob,
string name, ILogger log)
{
try
{
using var zip = new ZipArchive(inputBlob);
foreach (var item in zip.Entries)
{
using var stream = item.Open();
stream.CopyTo(outputBlob);
stream.Close();
}
outputBlob.Seek(0, SeekOrigin.Begin);
outputBlob.Close();
}
catch (Exception ex)
{
log.Log(LogLevel.Error, $"Error at {name}: {ex.Message}");
throw;
}
}
我们可以从 VSCode 进行调试以了解问题出在哪里,为此我们需要在 local.settings.json
文件中将 AzureWebJobsStorage
添加到 UseDevelopmentStorage=true
下面是 local.settings.json 文件的样子:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"unziptools_STORAGE": "DefaultEndpointsProtocol=https;AccountName=unziptools;AccountKey=XXXXXXXXX;EndpointSuffix=core.windows.net",
}
}
与您定义的方式类似,我们需要指定 blobtrigger :
[BlobTrigger("input-files/{name}", Connection = "cloud5mins_storage")]Stream myBlob
同时获取目标容器以加载解压文件:
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(destinationStorage);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference(destinationContainer);
下面是获取输入 blob 并将其放入目标存储和容器的示例代码。
public static async Task Run([BlobTrigger("input-files/{name}", Connection = "cloud5mins_storage")]CloudBlockBlob myBlob, string name, ILogger log)
{
log.LogInformation($"C# Blob trigger function Processed blob\n Name:{name}");
string destinationStorage = Environment.GetEnvironmentVariable("destinationStorage");
string destinationContainer = Environment.GetEnvironmentVariable("destinationContainer");
try{
if(name.Split('.').Last().ToLower() == "zip"){
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(destinationStorage);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference(destinationContainer);
using(MemoryStream blobMemStream = new MemoryStream()){
await myBlob.DownloadToStreamAsync(blobMemStream);
using(ZipArchive archive = new ZipArchive(blobMemStream))
{
foreach (ZipArchiveEntry entry in archive.Entries)
{
log.LogInformation($"Now processing {entry.FullName}");
//Replace all NO digits, letters, or "-" by a "-" Azure storage is specific on valid characters
string valideName = Regex.Replace(entry.Name,@"[^a-zA-Z0-9\-]","-").ToLower();
CloudBlockBlob blockBlob = container.GetBlockBlobReference(valideName);
using (var fileStream = entry.Open())
{
await blockBlob.UploadFromStreamAsync(fileStream);
}
}
}
}
}
}
catch(Exception ex){
log.LogInformation($"Error! Something went wrong: {ex.Message}");
}
}
感谢 frankynotes。
,我们有一个博客,其中包含有关此内容的详细信息
接受的答案大部分是我需要的,但有一些我不需要的非功能代码和检查。对于文档,我将工作修改后的代码放在这里:
[FunctionName("name")]
public static async Task Run(
[BlobTrigger("input-blob-container/{name}", Connection = "AzureWebJobsStorage")]Stream inputBlob,
string name, ILogger log)
{
try
{
log.Log(LogLevel.Information, "Starting unzip.");
string destinationStorage = Environment.GetEnvironmentVariable("destinationStorage");
string destinationContainer = Environment.GetEnvironmentVariable("destinationContainer");
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(destinationStorage);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference(destinationContainer);
using ZipArchive archive = new ZipArchive(inputBlob);
foreach (ZipArchiveEntry entry in archive.Entries)
{
log.LogInformation($"Now processing {entry.FullName}");
CloudBlockBlob blockBlob = container.GetBlockBlobReference(entry.Name);
await using var fileStream = entry.Open();
await blockBlob.UploadFromStreamAsync(fileStream);
}
log.Log(LogLevel.Information, "Finished unzip.");
}
catch (Exception ex)
{
log.Log(LogLevel.Error, $"Error at {name}: {ex.Message}");
throw;
}
}
还有我的local.settings.json
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"destinationStorage": "DefaultEndpointsProtocol=https;AccountName=azuresitename;AccountKey=;BlobEndpoint=https://azuresitename.blob.core.windows.net/;TableEndpoint=https://azuresitename.table.core.windows.net/;QueueEndpoint=https://azuresitename.queue.core.windows.net/;FileEndpoint=https://azuresitename.file.core.windows.net/",
"destinationContainer" : "output-blob-container"
}
}
我使用 Azure 扩展通过 VS Code 添加了 destinationStorage
和 destinationContainer
设置(在已接受答案的博客 post 中的视频中有详细介绍)。
这个概念验证的工作流程是:
- Azure Function App 在 blob 存储中检测到 .zip 文件 (
Stream inputBlob
) - 函数应用程序调用我的代码,它需要提取文件并将它们单独保存到 Blob 存储容器
Stream outputBlob
代码确实从 inputBlob
获取了 .zip,我可以在调试器中看到 ZipArchive
包含 .zip 的内容。但是没有文件输出,没有错误。我需要做什么才能将所有文件保存到 outputBlob
流?我确定我遗漏了与流复制相关的内容。
[FunctionName("Name")]
public static void Run(
[BlobTrigger("input/{name}", Connection = "AzureWebJobsStorage")]Stream inputBlob,
[Blob("output/{name}", FileAccess.Write)] Stream outputBlob,
string name, ILogger log)
{
try
{
using var zip = new ZipArchive(inputBlob);
foreach (var item in zip.Entries)
{
using var stream = item.Open();
stream.CopyTo(outputBlob);
stream.Close();
}
outputBlob.Seek(0, SeekOrigin.Begin);
outputBlob.Close();
}
catch (Exception ex)
{
log.Log(LogLevel.Error, $"Error at {name}: {ex.Message}");
throw;
}
}
我们可以从 VSCode 进行调试以了解问题出在哪里,为此我们需要在 local.settings.json
文件中将 AzureWebJobsStorage
添加到 UseDevelopmentStorage=true
下面是 local.settings.json 文件的样子:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"unziptools_STORAGE": "DefaultEndpointsProtocol=https;AccountName=unziptools;AccountKey=XXXXXXXXX;EndpointSuffix=core.windows.net",
}
}
与您定义的方式类似,我们需要指定 blobtrigger :
[BlobTrigger("input-files/{name}", Connection = "cloud5mins_storage")]Stream myBlob
同时获取目标容器以加载解压文件:
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(destinationStorage);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference(destinationContainer);
下面是获取输入 blob 并将其放入目标存储和容器的示例代码。
public static async Task Run([BlobTrigger("input-files/{name}", Connection = "cloud5mins_storage")]CloudBlockBlob myBlob, string name, ILogger log)
{
log.LogInformation($"C# Blob trigger function Processed blob\n Name:{name}");
string destinationStorage = Environment.GetEnvironmentVariable("destinationStorage");
string destinationContainer = Environment.GetEnvironmentVariable("destinationContainer");
try{
if(name.Split('.').Last().ToLower() == "zip"){
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(destinationStorage);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference(destinationContainer);
using(MemoryStream blobMemStream = new MemoryStream()){
await myBlob.DownloadToStreamAsync(blobMemStream);
using(ZipArchive archive = new ZipArchive(blobMemStream))
{
foreach (ZipArchiveEntry entry in archive.Entries)
{
log.LogInformation($"Now processing {entry.FullName}");
//Replace all NO digits, letters, or "-" by a "-" Azure storage is specific on valid characters
string valideName = Regex.Replace(entry.Name,@"[^a-zA-Z0-9\-]","-").ToLower();
CloudBlockBlob blockBlob = container.GetBlockBlobReference(valideName);
using (var fileStream = entry.Open())
{
await blockBlob.UploadFromStreamAsync(fileStream);
}
}
}
}
}
}
catch(Exception ex){
log.LogInformation($"Error! Something went wrong: {ex.Message}");
}
}
感谢 frankynotes。
,我们有一个博客,其中包含有关此内容的详细信息接受的答案大部分是我需要的,但有一些我不需要的非功能代码和检查。对于文档,我将工作修改后的代码放在这里:
[FunctionName("name")]
public static async Task Run(
[BlobTrigger("input-blob-container/{name}", Connection = "AzureWebJobsStorage")]Stream inputBlob,
string name, ILogger log)
{
try
{
log.Log(LogLevel.Information, "Starting unzip.");
string destinationStorage = Environment.GetEnvironmentVariable("destinationStorage");
string destinationContainer = Environment.GetEnvironmentVariable("destinationContainer");
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(destinationStorage);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference(destinationContainer);
using ZipArchive archive = new ZipArchive(inputBlob);
foreach (ZipArchiveEntry entry in archive.Entries)
{
log.LogInformation($"Now processing {entry.FullName}");
CloudBlockBlob blockBlob = container.GetBlockBlobReference(entry.Name);
await using var fileStream = entry.Open();
await blockBlob.UploadFromStreamAsync(fileStream);
}
log.Log(LogLevel.Information, "Finished unzip.");
}
catch (Exception ex)
{
log.Log(LogLevel.Error, $"Error at {name}: {ex.Message}");
throw;
}
}
还有我的local.settings.json
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"destinationStorage": "DefaultEndpointsProtocol=https;AccountName=azuresitename;AccountKey=;BlobEndpoint=https://azuresitename.blob.core.windows.net/;TableEndpoint=https://azuresitename.table.core.windows.net/;QueueEndpoint=https://azuresitename.queue.core.windows.net/;FileEndpoint=https://azuresitename.file.core.windows.net/",
"destinationContainer" : "output-blob-container"
}
}
我使用 Azure 扩展通过 VS Code 添加了 destinationStorage
和 destinationContainer
设置(在已接受答案的博客 post 中的视频中有详细介绍)。