Хранилище 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 МБ.
Учитывая обстоятельства (окружающая среда, размеры файлов...), которые подходят, как вы думаете, лучше?
Ответы
Ответ 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, который будет считаться обычной транзакцией (это будет стоить вам денег другими словами).