【问题标题】:Unzip files and save them to a Blob Storage stream解压缩文件并将它们保存到 Blob 存储流
【发布时间】:2021-10-20 19:57:01
【问题描述】:

我的这个概念证明的工作流程是:

  1. Azure Function App 检测到 Blob 存储中的 .zip 文件 (Stream inputBlob)
  2. 函数应用调用我的代码,需要提取文件并将它们单独保存到 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;
    }
}

【问题讨论】:

  • 旁注:将 ZIP 存档的内容转储到单个文件中(连接流甚至不注意顺序)似乎是一种奇怪的操作......也很不清楚你对 Seek 的期望 -可能需要为该行添加解释。
  • @AlexeiLevenkov 也许我用错了,我不希望将 zip 的内容放在一个文件中。 outputBlob 是一个 Azure Blob 存储位置,我希望将所有文件解压缩到该位置。搜索是从另一个类似功能复制粘贴,我实际上不知道我是否需要它。

标签: c# azure-functions zip filestream


【解决方案1】:

我们可以通过 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,我们有一个博客,里面有详细的信息。

【讨论】:

  • 提供的代码在await myBlob.DownloadToStreamAsync(blobMemStream); 不起作用,说“Stream 不包含 DownloadToStreamAsync 的定义”。也不清楚destinationStoragedestinationContainer 应该是什么值。它们是否与 BlobTrigger/Blob 属性中的 BlobPath 参数相同?
  • 经过修改,我能够让它工作。
  • @zakparks31191 很高兴,它帮助了你。
【解决方案2】:

接受的答案主要是我需要的,但有一些我不需要的非功能代码和检查。对于文档,我将工作修改代码放在这里:

[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 添加了 destinationStoragedestinationContainer 设置(在已接受答案的博客文章中的视频中有详细说明)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-13
    • 2021-11-19
    • 1970-01-01
    • 1970-01-01
    • 2021-12-03
    • 2020-02-11
    • 2020-12-16
    • 1970-01-01
    相关资源
    最近更新 更多