@[toc]
前言
上一篇net core WebApi——文件分片上傳與跨域請求處理介紹完文件的上傳操作场勤,本來是打算緊接著寫文件下載咨堤,中間讓形形色色的事給耽誤的立倍,今天還是抽個空整理完文件這塊兒镰绎,然后就可以鼓搗別的東西了朝卒。
開始
這里我們仍然使用基礎工程,需要下載的朋友請移步net core Webapi 總目錄香椎,代碼都是與博客的進度基本同步的漱竖。
上傳的時候我們介紹過分片的思路,而下載也一樣畜伐,只是客戶端與服務端角色轉換下就好了馍惹。
后端
- 接收前端下載請求,校驗請求信息,返回文件基本信息
- 根據前端請求文件片段進行下載流處理万矾。
前端
- 向后端發(fā)起下載請求悼吱,獲取文件總片段數
- 根據片段數循環(huán)請求文件片段流進行下載(可單獨請求某一片段文件數據)
文件下載相對于上傳來說稍微簡潔點兒,如果不考慮服務器壓力也可以一個a標簽解決下載問題良狈,分片的意義就在于每次與服務端的交互減少流量后添,有些時候我們推薦拿空間換時間,但對于大流量來說還是慢慢來比較好薪丁,單次訪問量如果大再加上多并發(fā)怕是服務器會受不了遇西,所以有了一片片分步來循環(huán)訪問這個方法。
也是直接來看代碼吧严嗜,我們在FileController創(chuàng)建幾個接口方法RequestDownloadFile努溃,FileDownload。
/// <summary>
/// 請求下載文件
/// </summary>
/// <param name="fileInfo">文件參數信息[name]</param>
/// <returns></returns>
[HttpPost, Route("RequestDownload")]
public MessageEntity RequestDownloadFile([FromBody]Dictionary<string, object> fileInfo)
{
}
/// <summary>
/// 分段下載文件
/// </summary>
/// <param name="fileInfo">請求參數信息[index,name]</param>
/// <returns></returns>
[HttpPost, Route("Download")]
public async Task<IActionResult> FileDownload([FromBody]Dictionary<string, object> fileInfo)
{
}
RequestDownloadFile
這里說明下阻问,與服務端的操作都要盡可能多的確認身份信息(當然后續(xù)會有說這塊兒),文件的相關操作也一樣需要并且還要嚴格點兒沦疾,我這里就是為了做示例演示所以只傳文件信息即可称近。
public MessageEntity RequestDownloadFile([FromBody]Dictionary<string, object> fileInfo)
{
MessageEntity message = new MessageEntity();
string fileName = string.Empty;
string fileExt = string.Empty;
if (fileInfo.ContainsKey("name"))
{
fileName = fileInfo["name"].ToString();
}
if (fileInfo.ContainsKey("ext"))
{
fileExt = fileInfo["ext"].ToString();
}
if (string.IsNullOrEmpty(fileName))
{
message.Code = -1;
message.Msg = "文件名不能為空";
return message;
}
//獲取對應目錄下文件,如果有哮塞,獲取文件開始準備分段下載
string filePath = $".{AprilConfig.FilePath}{DateTime.Now.ToString("yyyy-MM-dd")}/{fileName}";
filePath = $"{filePath}{fileExt}";
FileStream fs = null;
try
{
if (!System.IO.File.Exists(filePath))
{
//文件為空
message.Code = -1;
message.Msg = "文件尚未處理完";
return message;
}
fs = new FileStream(filePath, FileMode.Open);
if (fs.Length <= 0)
{
//文件為空
message.Code = -1;
message.Msg = "文件尚未處理完";
return message;
}
int shardSize = 1 * 1024 * 1024;//一次1M
RequestFileUploadEntity request = new RequestFileUploadEntity();
request.fileext = fileExt;
request.size = fs.Length;
request.count = (int)(fs.Length / shardSize);
if ((fs.Length % shardSize) > 0)
{
request.count += 1;
}
request.filedata = GetCryptoString(fs);
message.Data = request;
}
catch (Exception ex)
{
LogUtil.Debug($"讀取文件信息失斉俑选:{filePath},錯誤信息:{ex.Message}");
}
finally
{
if (fs != null)
{
fs.Close();
}
}
return message;
}
FileDownload
public async Task<IActionResult> FileDownload([FromBody]Dictionary<string, object> fileInfo)
{
//開始根據片段來下載
int index = 0;
if (fileInfo.ContainsKey("index"))
{
int.TryParse(fileInfo["index"].ToString(), out index);
}
else
{
return Ok(new { code = -1, msg = "缺少參數" });
}
string fileName = string.Empty;
string fileExt = string.Empty;
if (fileInfo.ContainsKey("name"))
{
fileName = fileInfo["name"].ToString();
}
if (fileInfo.ContainsKey("ext"))
{
fileExt = fileInfo["ext"].ToString();
}
if (string.IsNullOrEmpty(fileName))
{
return Ok(new { code = -1, msg = "文件名不能為空" });
}
//獲取對應目錄下文件衡未,如果有缓醋,獲取文件開始準備分段下載
string filePath = $".{AprilConfig.FilePath}{DateTime.Now.ToString("yyyy-MM-dd")}/{fileName}";
filePath = $"{filePath}{fileExt}";
if (!System.IO.File.Exists(filePath))
{
return Ok(new { code = -1, msg = "文件尚未處理" });
}
using (var fs = new FileStream(filePath, FileMode.Open))
{
if (fs.Length <= 0)
{
return Ok(new { code = -1, msg = "文件尚未處理" });
}
int shardSize = 1 * 1024 * 1024;//一次1M
int count = (int)(fs.Length / shardSize);
if ((fs.Length % shardSize) > 0)
{
count += 1;
}
if (index > count - 1)
{
return Ok(new { code = -1, msg = "無效的下標" });
}
fs.Seek(index * shardSize, SeekOrigin.Begin);
if (index == count - 1)
{
//最后一片 = 總長 - (每次片段大小 * 已下載片段個數)
shardSize = (int)(fs.Length - (shardSize * index));
}
byte[] datas = new byte[shardSize];
await fs.ReadAsync(datas, 0, datas.Length);
//fs.Close();
return File(datas, "application/x-gzip");
}
}
看過上傳的朋友都清楚上傳是三步,請求上傳=>開始上傳=>合并绊诲,而下載只需要兩步送粱,因為合并與否其實不那么重要了,反正文件流都給客戶端了掂之,那邊自己判斷需要重新下載還是下載部分片段都是他們自己的事了(服務端只管賣抗俄,東西有問題自己解決,多理想的狀態(tài))世舰。
測試
搞完之后重新生成动雹,運行之后我們來測試下效果,測試之前不要忘了接口白名單(做過登錄相關的驗證操作的忽略這點)跟压。
這里提示error是因為解析錯誤胰蝠,實際請求下載測試是正常的,如果有異常問題可以與我聯(lián)系姊氓。
小結
文件相關的上傳下載以及常規(guī)信息的操作可以告一段落丐怯,至于下一步鼓搗點兒啥也還沒想好读跷,本來還在看著linux相關的操作做發(fā)布部署的鋪墊,看最近總體的進度吧禾唁,總之,學如逆水行舟荡短,如果不想溺水丐枉,就握好你的漿(當然有些人不用漿那就算了瘦锹,告辭)弯院。