web-dev-qa-db-ja.com

Azure Blobストレージ:DownloadToByteArray VS DownloadToStream

Azure WebページでホストされるWebページのコンテキストでファイルを保存/回復するために、Azure Blob Storageサービスで遊んでいます。

学習プロセスの間に、2つのソリューションがありました。最初は基本的にDownloadToStreamを使用しますが、これはFileStreamを使用して同じことを行います。この場合、ユーザーに返す前にファイルをサーバーに書き込む必要があります。

public static Stream GetFileContent(string fileName, HttpContextBase context)
{
      CloudBlobContainer container = GetBlobContainer();    
      CloudBlockBlob blockBlob = container.GetBlockBlobReference(fileName);                                       
      Stream fileStream = new FileStream(
          context.Server.MapPath("~/App_Data/files/" + fileName), FileMode.Create);   
      blockBlob.DownloadToStream(fileStream);
      fileStream.Close();    
      return File.OpenRead(context.Server.MapPath("~/App_Data/files/" + fileName));
}

public ActionResult Download(string fileName)
{
    byte[] fileContent = MyFileContext.GetFileContent(fileName);
    return File(fileContent, "application/Zip", fileName);        
}

一方、DownloadToByteArray関数を使用して、BlobのコンテンツをBlobファイルのサイズで初期化されたバイト配列に書き込みます。

public static byte[] GetFileContent(string fileName)
{
    CloudBlobContainer container = GetBlobContainer();           
    CloudBlockBlob blockBlob = container.GetBlockBlobReference(fileName);
    blockBlob.FetchAttributes();
    long fileByteLength = blockBlob.Properties.Length;
    byte[] fileContent = new byte[fileByteLength];
    for (int i = 0; i < fileByteLength; i++)
    {
        fileContent[i] = 0x20;
    }
    blockBlob.DownloadToByteArray(fileContent,0);
    return fileContent;
}

public ActionResult Download(string fileName)
{   
   byte[] fileContent = MyFileContext.GetFileStream(fileName);
   return File(fileContent, "application/Zip", fileName);
}

両方のオプションを見ると、1つ目はサーバーのディスクにファイルを作成する必要があり、2つ目はBlobからのデータをメモリを消費するバイト配列に保存する必要があることがわかります。私の特定のケースでは、最大150 MBのファイルサイズを処理します。

状況(環境、ファイルサイズなど)を考えると、どのアプローチが最適だと思いますか?

31
Julen

Streamの利点は、大きなbyte []を構築してからすべてを操作するのではなく、ダウンロード時にビットごとに処理できることです。 Streamを使用しても、ファイルに書き込んでからそのファイル全体をメモリに読み込むため、実際には利点が得られません。ストリームAPIの適切な使用方法は、こちらの回答に示されているように、ダウンロードストリームをリクエストの応答ストリームに直接パイプすることです MVC3でのAzure Blobファイルのダウンロード

19
Robert Levy

サーバーを介してBlobをストリーミングする代わりに、Blobストレージから直接ダウンロードできます。私の答えは、スティーブの応答の上に構築されています: MVC3でのAzure Blobファイルのダウンロード 。ストレージから直接blobをダウンロードするには、Shared Access Signature (SAS)を利用します。最近、Azure Storageに拡張機能が導入され、SASでContent-Dispositionヘッダーを指定できるようになりました。この変更されたコードを参照してください。

    public static string GetDownloadLink(string fileName)
    {
        CloudBlobContainer container = GetBlobContainer();
        CloudBlockBlob blockBlob = container.GetBlockBlobReference(fileName);
        //Create an ad-hoc Shared Access Policy with read permissions which will expire in 12 hours
        SharedAccessBlobPolicy policy = new SharedAccessBlobPolicy()
        {
            Permissions = SharedAccessBlobPermissions.Read,
            SharedAccessExpiryTime = DateTime.UtcNow.AddHours(12),
        };
        //Set content-disposition header for force download
        SharedAccessBlobHeaders headers = new SharedAccessBlobHeaders()
        {
            ContentDisposition = string.Format("attachment;filename=\"{0}\"", fileName),
        };
        var sasToken = blockBlob.GetSharedAccessSignature(policy, headers);
        return blockBlob.Uri.AbsoluteUri + sasToken;
    }

    public ActionResult Download(string fileName)
    {
        var sasUrl = GetDownloadLink(fileName);
        //Redirect to SAS URL ... file will now be downloaded directly from blob storage.
        Redirect(sasUrl);
    }
27
Gaurav Mantri

DownloadToBytesArray(非同期かどうか)を使用する予定の場合、最初にblob属性をフェッチして、バイト配列の初期サイズを取得する必要があります。

DownloadToStreamを使用する場合は、その必要はありません。それは保存されたblobストレージへのHTTP呼び出しの1つであり、私が間違っていなければ、FetchAttributes()はHTTP HEAD要求として実行され、通常のトランザクションとしてカウントされます(つまり、いくらかお金がかかります)。

14
Zygimantas