原有系統的附件都是保存在服務器上的,占用了大量的磁盤空間,如今要切換到AWS S3上做文件存儲管理。文件打包下載之前的做法是,后台將文件服務器上的多個文件打包到一個壓縮文件中,存放在服務器,后端接口返回壓縮文件地址供前端下載;為此,特寫下這篇文章來記錄此處是如何根據文件流來制作壓縮包的。
AWS S3更多存取文件的demo需看官方源碼,本文中有下載的實例。
需要引用:AWSSDK.Core、AWSSDK.S3,可從NuGet安裝;
需要引用:System.IO.Compression,可從NuGet安裝;
在ConfigureServices下單例注入AWS類
public void ConfigureServices(IServiceCollection services) { ....... services.AddSingleton<Aws>(); ......... }
Configure下獲取AWS實例
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { //......// Aws.Instance = app.ApplicationServices.GetService<Aws>(); }
AWS類
public class Aws { #region Init private readonly IConfiguration _cfg; /// <summary> /// 存儲桶名稱 /// </summary> private string bucketName; /// <summary> /// aws Id /// </summary> private readonly string awsAccessKeyId; /// <summary> /// aws Id key /// </summary> private readonly string awsSecretAccessKey; private IAmazonS3 client; private AmazonS3Config config = new AmazonS3Config() { ServiceURL = "http://s3.amazonaws.com", RegionEndpoint = Amazon.RegionEndpoint.CNNorth1 //賬號在哪個區域就用哪個區域,不然會出現賬號401的問題 }; #endregion public Aws(IConfiguration cfg) { _cfg = cfg; awsAccessKeyId = _cfg["AccessKeyId"]; awsSecretAccessKey = _cfg["SecretAccessKey"]; bucketName = _cfg["BucketName"]; client = new AmazonS3Client(awsAccessKeyId, awsSecretAccessKey, config); } /// <summary> /// AWS文件批量下載 /// </summary> /// <param name="fileName">文件相對地址(aws key)</param> /// <returns></returns> public async Task<byte[]> BatchDownload(List<string> fileNames) { try { byte[] res; using (MemoryStream ms = new MemoryStream()) { using (ZipArchive zip = new ZipArchive(ms, ZipArchiveMode.Create, true)) { foreach (var fileName in fileNames) { //通過aws下載文件流 var response = await client.GetObjectAsync(bucketName, newfileName); var pdfStream= response.ResponseStream;//得到文件流 var pdfBytes = StringHelper.StreamToBytes(pdfStream);//文件流轉換成字節 ZipArchiveEntry entry = zip.CreateEntry("abc.pdf");//壓縮文件內創建一個文件名為“abc.pdf”,流是什么文件格式就用什么格式,此處我的是pdf格式 using (Stream sw = entry.Open()) { sw.Write(pdfBytes, 0, pdfBytes.Length);//將文件的字節寫到abc.pdf中 } } InvokeWriteFile(zip);//重新計算壓縮文件的大小,此處參考別人的 int nowPos = (int)ms.Position; res = new byte[ms.Length]; ms.Position = 0; ms.Read(res, 0, res.Length); ms.Position = nowPos; } return res; } } catch (Exception ex) { throw ex; } } public void InvokeWriteFile(ZipArchive zipArchive) { foreach (MethodInfo method in zipArchive.GetType().GetRuntimeMethods()) { if (method.Name == "WriteFile") { method.Invoke(zipArchive, new object[0]); } } } }
控制器下載壓縮文件
/// <summary> /// 批量下載 /// </summary> /// <param name="ids"></param> /// <returns></returns> public async Task<IActionResult> Packing(List<int> ids) { var paths = new List<string>(); //根據Id查詢本地對應的文件名稱,Id換取文件名稱 var bytes = await Aws.Instance.BatchDownload(paths).ToList()); Response.ContentType = "application/octet-stream"; var contentDisposition = "attachment;" + "filename=" + HttpUtility.UrlEncode("XXXX.zip"); Response.Headers.Add("Content-Disposition", new string[] { contentDisposition }); Response.ContentLength = bytes.Length; Response.Body.Write(bytes, 0, bytes.Length);//發送讀取的內容數據到客戶端瀏覽器 Response.Body.Flush(); return new EmptyResult(); }
前端Ajax調用
//后端返回的是文件流 var ids = [1,2,3]; var url = "/PackingByAws"; var form = $("<form></form>").attr("action", url).attr("method", "post"); ////后端為List<Int>參數 ids.forEach(function (value) { form.append($("<input></input>").attr("type", "hidden").attr("name", "ids").attr("value", value)); }) form.appendTo('body').submit().remove();
第一次寫文章,從業也有幾年了,一直都是拿來主義。這篇文件也是近期項目遇到的特拿來分享,也是懷着無比忐忑的心情才寫下來的,寫的不好的地方還請見諒。
作者:佐小陌
鏈接:https://www.jianshu.com/p/aab752964f4e
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。