Подтвердить что ты не робот

Хранилище Azure Blob: DownloadToByteArray VS DownloadToStream

Я играл с сервисом хранения Azure Blob для сохранения/восстановления файлов в контексте веб-страницы, которая будет размещаться на веб-страницах Azure.

В процессе обучения я пришел с двумя решениями; первый в основном использует 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);
}

Когда я смотрю на оба варианта, я вижу, что сначала нужно создать файл на диске сервера, а второй хранит данные из Blob в байтовой памяти, потребляющей память. В моем конкретном случае я собираюсь обрабатывать файлы размером ~ 150 МБ.

Учитывая обстоятельства (окружающая среда, размеры файлов...), которые подходят, как вы думаете, лучше?

4b9b3361

Ответ 1

Преимущество Stream заключается в том, что вы можете обрабатывать биты по частям, поскольку они загружаются, а не строят большой байт [], а затем работают на полной основе. Использование Stream не дает преимуществ, поскольку вы пишете файл, а затем читаете этот полный файл в памяти. Хорошим использованием API потока является то, что он будет транслировать поток загрузки непосредственно в поток ответа на запрос, как показано в ответе здесь Загрузка файлов Azure Blob в MVC3

Ответ 2

Вместо потоковой передачи blob через ваш сервер вы можете загрузить его непосредственно из хранилища blob. Мой ответ построен поверх ответа Стива здесь: Загрузка файлов Azure Blob в MVC3. Для загрузки blob непосредственно из хранилища вы должны использовать Shared Access Signature (SAS). Недавно Azure Storage внедрила усовершенствование, которое позволяет указать заголовок Content-Disposition в SAS. См. Этот измененный код.

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

Ответ 3

Если вы планируете использовать DownloadToBytesArray (асинхронно или нет), вам сначала нужно будет получить атрибуты blob, чтобы получить начальный размер байтового массива.

И если вы будете использовать DownloadToStream, вам не придется этого делать. Тот, кто сохранил HTTP-вызов в хранилище blob, и если я не ошибаюсь, FetchAttributes() выполняется как запрос HTTP HEAD, который будет считаться обычной транзакцией (это будет стоить вам денег другими словами).