2014-06-19 22 views
20

Tôi đã phát bằng dịch vụ Lưu trữ Azure Blob để lưu/khôi phục tệp trong ngữ cảnh của một trang web được lưu trữ trong Trang Web Azure.Lưu trữ Azure Blob: Tải xuốngToByteArray VS DownloadToStream

Trong quá trình tìm hiểu, tôi đã đi kèm với hai giải pháp; đầu tiên về cơ bản sử dụng DownloadToStream làm tương tự nhưng với FileStream. Trong trường hợp này, tôi phải ghi tệp trong máy chủ trước khi trả lại cho người dùng.

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

Mặt khác tôi đã sử dụng chức năng DownloadToByteArray với ghi nội dung của Blob trong một mảng byte khởi tạo với kích thước của tập tin 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); 
} 

Khi tôi xem xét cả hai tùy chọn, tôi thấy nhu cầu đầu tiên tạo tệp trong đĩa của máy chủ trong khi thứ hai lưu trữ dữ liệu từ Blob trong mảng byte tiêu thụ bộ nhớ. Trong trường hợp cụ thể của tôi, tôi sẽ xử lý kích thước tập tin của ~ 150 MB.

Với hoàn cảnh (môi trường, kích thước tệp ...) bạn nghĩ cách tiếp cận nào là tốt nhất?

+0

Mục tiêu của bạn có luôn luôn tải xuống các tệp trên máy tính của người dùng không? Hay nói cách khác, bạn có muốn xử lý dữ liệu này trước khi truyền dữ liệu đến trình duyệt của người dùng hay không, bạn có thể trực tiếp tải xuống tệp trên máy tính của người dùng từ bộ nhớ Azure không? –

+0

Chỉ để không mất dấu của một cái gì đó: 'DownloadToStream' đòi hỏi một' Stream' nhưng 'FileStream' không phải là loại luồng duy nhất xung quanh. – CyberDude

+0

@GauravMantri có, ý tưởng là chỉ để donwload các tập tin mà không thực hiện bất kỳ hoạt động với nó. – Julen

Trả lời

11

Lợi ích của luồng là bạn có thể xử lý từng bit một khi chúng được tải xuống thay vì xây dựng một byte lớn [] và sau đó hoạt động trên toàn bộ. Việc bạn sử dụng Luồng không thực sự nhận được lợi ích từ khi bạn đang viết vào một tệp và sau đó đọc toàn bộ tệp đó vào bộ nhớ. Sử dụng tốt API luồng sẽ cho phép luồng tải xuống trực tiếp vào luồng phản hồi của yêu cầu như được hiển thị trong câu trả lời tại đây Downloading Azure Blob files in MVC3

+0

Cảm ơn Robert. Giải pháp này phù hợp hơn trong dự án của tôi. – Julen

19

Thay vì phát trực tiếp blob qua máy chủ của bạn, bạn có thể tải xuống trực tiếp từ bộ nhớ blob. Câu trả lời của tôi được xây dựng dựa trên câu trả lời của Steve ở đây: Downloading Azure Blob files in MVC3. Để tải xuống một blob trực tiếp từ bộ nhớ, bạn sẽ sử dụng Shared Access Signature (SAS). Gần đây Azure lưu trữ đã giới thiệu một nâng cao, cho phép bạn chỉ định Content-Disposition tiêu đề trong SAS. Xem mã đã sửa đổi này.

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

Cảm ơn! Nó hoạt động tốt đẹp! Một câu hỏi khó khăn, nên được coi là một lỗ hổng bảo mật tiềm năng để mở các điều khoản? Trong giải pháp của tôi, tôi thiết lập một cửa sổ 30 giây. – Julen

+3

Thời gian hết hạn được chia sẻ trong ví dụ của tôi chỉ dành cho mục đích trình diễn. Bạn nên đặt nó dựa trên thời gian bạn nghĩ rằng người dùng của bạn sẽ cần phải tải xuống tệp. Nếu bạn nghĩ rằng, người dùng của bạn có thể tải xuống tệp trong 30 giây, bạn có thể đặt tệp đó thành giá trị đó. Bạn có thể muốn đọc bài đăng trên blog này để biết các phương pháp hay nhất của SAS: http://blogs.msdn.com/b/windowsazurestorage/archive/2012/06/12/introducing-table-sas-shared-access-signature-queue-sas -and-update-to-blob-sas.aspx. HTH. –

+0

Điều quan trọng cần lưu ý là thời gian chờ của mã thông báo SAS cho biết khi nào không thể bắt đầu tải xuống nữa. Miễn là quá trình tải xuống bắt đầu trước khi hết hạn mã thông báo SAS, quá trình tải xuống có thể mất nhiều thời gian hơn thời gian tải xuống và nó sẽ tải xuống tốt. –

9

Nếu bạn đang có kế hoạch sử dụng DownloadToBytesArray (async hay không), bạn sẽ phải lấy blob thuộc tính đầu tiên để có được một kích thước ban đầu của mảng byte.

Và nếu bạn sẽ sử dụng DownloadToStream bạn sẽ không phải làm điều đó. Đó là một lưu cuộc gọi HTTP để lưu trữ blob và nếu tôi không nhầm, FetchAttributes() được thực hiện như yêu cầu HTTP TRỤ và điều đó sẽ được tính là một giao dịch bình thường (nó sẽ giúp bạn tốn ít tiền hay nói cách khác).

+2

Tìm nạp các thuộc tính sẽ không thêm nhiều chi phí nhưng chắc chắn đáng để gọi. –

Các vấn đề liên quan