脚本的功能目的是在容器中接收一组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);
}
}
答案 0 :(得分:1)
看起来问题就在这里:
using (var entryStream = blobInArchive.Open())
using (var fileToCompressStream = new MemoryStream(blob.StreamWriteSizeInBytes))
{
fileToCompressStream.CopyTo(entryStream);
}
你的entryStream
是你写的流,为了添加到zip文件(如果我正确理解你的代码) - 所以没关系。
但是,您正在创建一个新的空 fileToCompressStream
,其中没有任何内容;你只是传入一个整数,这是流的大小(我不明白如何编译,但这是另一回事)。因此,您要在Zip文件中添加一个空流。
你应能够用这个替换上面三行(未经测试);
using (var entryStream = blobInArchive.Open())
{
blob.DownloadToStream(entryStream);
}
如果因奇怪的例外而失败 - 而且可能因为.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;
这对结果没有影响,我个人更喜欢这种语法。