前言
工作上剛好遇到需要將儲存體打包並下載的功能,所以整理了一下程式碼並寫成簡單範例。包含了列出儲存體容器內的檔案和打包下載的功能,壓縮的部分則是使用 SharpZipLib
套件來完成。
實做
準備儲存體和檔案
先建立好儲存體,並建立了一個容器名稱為 samplefile,並且上傳了幾個範例檔案。
取得儲存體的連線字串。
列出儲存體內檔案
新增一個 .NET 6 Razor Page 專案,並且新增 StorageKey
到設定檔內,值則為儲存體的連線字串
。新增相關 NuGet 套件:
新增 BlobFIleinfo
Model ,作為之後取得儲存體的相關資訊用。
public class BlobFIleinfo
{
/// <summary>
/// File Name
/// </summary>
[Display(Name = "File Name")]
public string Name { get; set; }
/// <summary>
/// File Size
/// </summary>
[Display(Name = "File Size")]
public long? Size { get; set; }
/// <summary>
/// ContentType
/// </summary>
[Display(Name = "ContentType")]
public string ContentType { get; set; }
}
新增 IStorageService 介面
public interface IStorageService
{
/// <summary>
/// Get Blob List
/// </summary>
/// <returns></returns>
List<BlobFIleinfo> GetBlobList();
/// <summary>
/// Download Blob
/// </summary>
/// <param name="blobName">Blob Name</param>
(byte[] File, string ContentType) DownloadBlob(string blobName);
/// <summary>
/// Zip Blobs
/// </summary>
/// <param name="fileNames">File Name</param>
/// <returns></returns>
byte[] ZipBlobs(List<string> fileNames);
}
實做 StorageService
/// <summary>
/// Storage Service
/// </summary>
public class StorageService : IStorageService
{
private readonly BlobServiceClient _blobServiceClient;
private const string containerName = "samplefile";
public StorageService(IConfiguration configuration)
{
string connectionString = configuration.GetValue<string>("StorageKey");
_blobServiceClient = new BlobServiceClient(connectionString);
}
/// <summary>
/// Get Blob List
/// </summary>
/// <returns></returns>
public List<BlobFIleinfo> GetBlobList()
{
var blobList = new List<BlobFIleinfo>();
BlobContainerClient container = _blobServiceClient.GetBlobContainerClient(containerName);
var blobPages = container.GetBlobs(BlobTraits.None).AsPages();
foreach (var blobPage in blobPages)
{
foreach (BlobItem blobItem in blobPage.Values)
{
blobList.Add(new BlobFIleinfo()
{
Name = blobItem.Name,
Size = blobItem.Properties.ContentLength,
ContentType = blobItem.Properties.ContentType
});
}
}
return blobList;
}
/// <summary>
/// Download Blob
/// </summary>
/// <param name="blobName">Blob Name</param>
public (byte[] File, string ContentType) DownloadBlob(string blobName)
{
BlobContainerClient container = _blobServiceClient.GetBlobContainerClient(containerName);
BlobClient blob = container.GetBlobClient(blobName);
if (blob.Exists())
{
MemoryStream file = new MemoryStream();
BlobDownloadInfo download = blob.Download();
download.Content.CopyTo(file);
return (file.ToArray(), blob.GetProperties().Value.ContentType);
}
else
return (null, null);
}
/// <summary>
/// Zip Blobs
/// </summary>
/// <param name="fileNames">File Name</param>
/// <returns></returns>
public byte[] ZipBlobs(List<string> fileNames)
{
using (var output = new MemoryStream())
using (var zipOutputStream = new ZipOutputStream(output))
{
zipOutputStream.SetLevel(9);
foreach (var fileName in fileNames)
{
BlobContainerClient container = _blobServiceClient.GetBlobContainerClient(containerName);
BlobClient blob = container.GetBlobClient(fileName);
var entry = new ZipEntry(fileName);
zipOutputStream.PutNextEntry(entry);
blob.DownloadTo(zipOutputStream);
}
zipOutputStream.Finish();
zipOutputStream.Close();
return output.ToArray();
}
}
}
修改 Index 檔案
@page
@model IndexModel
<h1>Blob List</h1>
<div class="form-check">
<form action="./ZipFile" method="get">
<table class="table">
<thead>
<tr>
<th></th>
<th>
@Html.DisplayNameFor(model => model.BlobFIleinfos[0].Name)
</th>
<th>
@Html.DisplayNameFor(model => model.BlobFIleinfos[0].Size)
</th>
<th>
@Html.DisplayNameFor(model => model.BlobFIleinfos[0].ContentType)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.BlobFIleinfos)
{
<tr>
<td>
<input name="fileName" class="form-check-input" type="checkbox" value="@item.Name" />
</td>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Size)
</td>
<td>
@Html.DisplayFor(modelItem => item.ContentType)
</td>
<td>
<a asp-page="./Download" asp-route-blobName="@item.Name">Download</a>
</td>
</tr>
}
</tbody>
</table>
<button type="submit" class="btn btn-primary">Zip Select Files</button>
</form>
</div>
修改 Index.cshtml.cs 檔案
public class IndexModel : PageModel
{
private readonly IStorageService _storageService;
public IndexModel(IStorageService storageService)
{
_storageService = storageService;
}
public IActionResult OnGet()
{
BlobFIleinfos = _storageService.GetBlobList();
return Page();
}
public List<BlobFIleinfo> BlobFIleinfos { get; set; }
}
新增 Download 頁面,因為沒有要呈現頁面,修改建立好的 Download.cshtml.cs 檔案
public class DownloadModel : PageModel
{
private readonly IStorageService _storageService;
public DownloadModel(IStorageService storageService)
{
_storageService = storageService;
}
public IActionResult OnGet(string blobName)
{
var blob = _storageService.DownloadBlob(blobName);
return File(blob.File, blob.ContentType, blobName);
}
}
新增 ZipFile 頁面,一樣修改 ZipFile.cshtml.cs 檔案即可
public class ZipFileModel : PageModel
{
private readonly IStorageService _storageService;
public ZipFileModel(IStorageService storageService)
{
_storageService = storageService;
}
public IActionResult OnGet(List<string> fileName)
{
var zipFile = _storageService.ZipBlobs(fileName);
return File(zipFile, "application/octet-stream", "ZipFile.zip");
}
}
到這邊就完成了所有功能,執行之後畫面如下呈現,會將儲存體內的檔案列出來,並且顯示檔案大小和類型,並且提供下載單一檔案和壓縮指定檔案功能。
完整程式碼可以到 GitHub 察看。
結論
目前功能就簡單實做了列表、單一檔案下載、打包選取下載,未來可以在加上更多功能,就可以實做出一個簡單的儲存體檔案總管功能。