块 Blob 的 Azure C# WebJob 归档集写入所有归档图像,字节数为 0

Azure C# WebJob Archiving Set of Block Blobs Writes All Archived Images with 0 Bytes

脚本的功能目的是在容器中接收一组 blob 名称。并创建一个可以稍后下载的 .ZIP 文件。

经过一些研究,我能够触发 WebJob 并将图像添加到存档中,然后将其上传回 Blob 存储。问题是所有文件都有零字节。我对 C# 中的 Streams 完全陌生,但一直在这样的前提下操作:我可以根据需要简单地传输数据,只需将最终存档流写回 blob 存储。

我的假设不正确吗?

我怀疑我的问题与循环浏览图像时的某些异步操作有关,这些操作在存档写入和上传之前永远不会完成。

代码如下,如有帮助将不胜感激!

public static void ArchiveImagesTask(
        [QueueTrigger("download")] AssetImagesArchive assetImages,
        string id,
        string email,
        string container,
        string[] images,
        [Blob("{container}")] CloudBlobContainer sourceContainer,
        [Blob("downloads")] CloudBlobContainer targetContainer)
{

    using (var memoryStream = new MemoryStream())
    {
        using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
        {
            foreach (var image in images)
            {
                var blobInArchive = archive.CreateEntry(image, CompressionLevel.Optimal);
                var blob = sourceContainer.GetBlockBlobReference(image);

                using (var entryStream = blobInArchive.Open())
                using (var fileToCompressStream = new MemoryStream(blob.StreamWriteSizeInBytes))
                {
                    fileToCompressStream.CopyTo(entryStream);
                }
            }
        }

        var zip = targetContainer.GetBlockBlobReference($"{id}.zip");
        memoryStream.Seek(0, SeekOrigin.Begin);
        zip.UploadFromStream(memoryStream);
    }
}

看来问题出在这里:

using (var entryStream = blobInArchive.Open())
using (var fileToCompressStream = new MemoryStream(blob.StreamWriteSizeInBytes))
 {
      fileToCompressStream.CopyTo(entryStream);
 }

您的 entryStream 是您写入的流,以便添加到 zip 文件(如果我正确理解您的代码)- 这样很好。 但是,您正在创建一个新的 empty fileToCompressStream,里面什么也没有;您只是传递一个整数,它是流的大小(我不明白它是如何编译的,但那是另一回事)。因此,您正在向 Zip 文件中添加一个空流。

应该可以用这个替换上面三行(未测试);

using (var entryStream = blobInArchive.Open())
{
    blob.DownloadToStream(entryStream);
}

参见 https://msdn.microsoft.com/en-us/library/microsoft.windowsazure.storage.blob.cloudblob.downloadtostream.aspx

如果 失败并出现奇怪的异常 - 它可能是因为 .Net 中的 Streams 在很大程度上违反了 Liskov 替换原则 - 你可能需要这样做;

using (var entryStream = blobInArchive.Open())
using (var fileToCompressStream = new MemoryStream(blob.StreamWriteSizeInBytes))
 {
      blob.DownloadToStream(fileToCompressStream);
      fileToCompressStream.Position = 0; // Not sure this is necessary
      fileToCompressStream.CopyTo(entryStream);
 }

...但只有在必要时才这样做;如果这样做,您将在内存中拥有整个文件的另一个副本。

如果在那之后您仍然遇到问题,您可能需要手动刷新一些流;您正在使用的 using 语句将调用流上的 Dispose 方法,应该 刷新它们,但总有可能有人没有正确实现它。

边注

你加入这一行是非常正确的:

memoryStream.Seek(0, SeekOrigin.Begin);

它将流中的指针设置回开头,这样当您上传它时,您实际上会向上发送数据。你可能想知道 MemoryStream 有一个稍微简单的方法来做到这一点,即:

memoryStream.Position = 0;

这对结果没有影响,我个人更喜欢这种语法。