web-dev-qa-db-fra.com

Stockage Azure Blob: DownloadToByteArray VS DownloadToStream

J'ai joué avec le service Azure Blob Storage pour enregistrer/récupérer des fichiers dans le contexte d'une page Web à héberger dans Azure Web Pages.

Au cours du processus d'apprentissage, je suis venu avec deux solutions; le premier utilise essentiellement DownloadToStream qui fait de même mais avec un FileStream. Dans ce cas, je dois écrire le fichier sur le serveur avant de le retourner à l'utilisateur.

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);        
}

D'un autre côté, j'ai utilisé la fonction DownloadToByteArray avec écrit le contenu du Blob dans un tableau d'octets initialisé avec la taille du fichier 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);
}

Quand je regarde les deux options, je vois que le premier doit créer un fichier sur le disque du serveur tandis que le second stocke les données du Blob dans une mémoire consommant un tableau d'octets. Dans mon cas particulier, je vais gérer des tailles de fichier de ~ 150 Mo.

Compte tenu des circonstances (environnement, taille des fichiers ...) quelle approche pensez-vous être la meilleure?

31
Julen

L'avantage de Stream est que vous pouvez traiter les bits morceau par morceau au fur et à mesure qu'ils sont téléchargés plutôt que de créer un gros octet [] et de fonctionner ensuite sur la totalité. Votre utilisation de Stream n'obtient pas vraiment les avantages car vous écrivez dans un fichier, puis lisez ce fichier complet en mémoire. Une bonne utilisation de l'API de flux serait de diriger le flux de téléchargement directement vers le flux de réponse de la demande, comme indiqué dans la réponse ici Téléchargement de fichiers Azure Blob dans MVC

19
Robert Levy

Au lieu de diffuser le blob via votre serveur, vous pouvez le télécharger directement à partir du stockage de blob. Ma réponse est basée sur la réponse de Steve ici: Téléchargement de fichiers Azure Blob dans MVC . Pour télécharger un blob directement à partir du stockage, vous utiliseriez Shared Access Signature (SAS). Récemment, Azure Storage a introduit une amélioration, qui vous permet de spécifier Content-Disposition en-tête dans SAS. Voir ce code modifié.

    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

Si vous prévoyez d'utiliser DownloadToBytesArray (asynchrone ou non), vous devrez d'abord récupérer les attributs de blob pour obtenir une taille initiale de tableau d'octets.

Et si vous utilisez DownloadToStream vous n'aurez pas à le faire. C'est un appel HTTP enregistré vers le stockage d'objets blob et si je ne me trompe pas, FetchAttributes () est exécuté comme HTTP HEAD request et cela comptera comme une transaction normale ( cela vous coûtera de l'argent en d'autres termes).

14
Zygimantas