块 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);
}
如果 失败并出现奇怪的异常 - 它可能是因为 .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;
这对结果没有影响,我个人更喜欢这种语法。
脚本的功能目的是在容器中接收一组 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);
}
如果 失败并出现奇怪的异常 - 它可能是因为 .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;
这对结果没有影响,我个人更喜欢这种语法。