问题
使用axios进行流处理文件下载的过程中,如果文件比较大,就需要等待整个文件流都下载到内存中才会弹出浏览器的下载文件保存对话框,这种方式在下载小文件的场景没什么问题,但是遇到大文件,一方面是浏览器的下载保存对话框半天都不会响应客户,这样体验不是很好;另外一方面是受到客户端内存的限制。
解决办法:
代码语言:javascript复制function downloadFileByUrl() {
var url = '/api/common/downloadFile?xxxx.srt'
fetch(url, {
method: 'GET',
cache: 'no-cache'
}).then(res => {
const fileStream = streamSaver.createWriteStream('文件名.mp4', {
size: res.headers.get("content-length")
})
const readableStream = res.body
// more optimized
if (window.WritableStream && readableStream.pipeTo) {
return readableStream.pipeTo(fileStream)
.then(() => console.log('done writing'))
}
window.writer = fileStream.getWriter()
const reader = res.body.getReader()
const pump = () => reader.read()
.then(res => res.done
? window.writer.close()
: window.writer.write(res.value).then(pump))
pump()
})
}
引用js附件
代码语言:javascript复制<script src="@Url.Content("~/")Static/js/streamSaver.js"></script>
需要修改streamSaver.js文件面的内容,配置成
代码语言:javascript复制//if you decide to host mitm sw yourself
streamSaver.mitm ='https://example.com/custom_mitm.html'
具体参考:streamSaver.js
StreamSaver
下载附件后端的几种方法:
代码语言:javascript复制/// <summary>
/// 下载附件
/// </summary>
/// <param name="id">附件ID</param>
/// <returns></returns>
[HttpGet, Route("api/file/download"), AllowAnonymous]
public HttpResponseMessage Download(Guid id)
{
HttpResponseMessage res = new HttpResponseMessage(HttpStatusCode.OK);
//附件路径
string fileNames= AppendixHelper.GetFileName(id, AppendixFormat.档案原始稿);
if (fileNames.Count == 0)
{
throw new Exception(MessageCode.CM0000);
}
else
{
res.Content = new StreamContent(new FileStream(fileNames[0], FileMode.Open));
res.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
}
return res;
}
方法二:
代码语言:javascript复制/// <summary>
///
/// </summary>
/// <param name="attachmentId"></param>
/// <returns></returns>
[HttpGet, HttpHead, Route("api/downloadT/{attachmentId}"), AllowAnonymous]
public IHttpActionResult DownloadServerT2(Guid? attachmentId)
{
if (!attachmentId.HasValue)
{
return ResponseMessage(new HttpResponseMessage(HttpStatusCode.BadRequest));
}
HttpResponseMessage res = new HttpResponseMessage(HttpStatusCode.OK);
var fileLength = 2000;//文件大小
var fileName = "http://xxxxxx/xxxxxx.pdf";//文件地址
HttpResponseMessage response = new HttpResponseMessage();
string MimeType = "application/octet-stream";
long speed = 1024 * 100;
long packSize = 1024 * 10;
int sleep = (int)Math.Ceiling(1000.0 * packSize / speed);//毫秒数:读取下一数据块的时间间隔
ContentInfo contentInfo = GetContentInfoFromRequest(this.Request, fileLength);
Action<Stream, HttpContent, TransportContext> pushContentAction = (outputStream, content, context) =>
{
try
{
int length = Convert.ToInt32((fileLength - 1) - contentInfo.From) 1;
while (length > 0 && packSize > 0)
{
WebClient wc = new WebClient();
wc.BaseAddress = fileName;
byte[] fdfs;
fdfs = wc.DownloadData(wc.BaseAddress);
outputStream.Write(fdfs, 0, fdfs.Length);
contentInfo.From = contentInfo.From fdfs.Length;
length -= fdfs.Length;
if (sleep > 1)
{
Thread.Sleep(sleep);
}
}
}
catch (HttpException ex)
{
throw ex;
}
finally
{
outputStream.Close();
}
};
response.Content = new PushStreamContent(pushContentAction, new MediaTypeHeaderValue(MimeType));
var browser = String.Empty;
if (Request.Headers.UserAgent != null)
{
browser = Request.Headers.UserAgent.ToString().ToUpper();
}
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") // 设置头部其他内容特性, 文件名
{
FileName = browser.Contains("FIREFOX") ? fileName : HttpUtility.UrlEncode(fileName)
};
return ResponseMessage(response);
}
方法三:
代码语言:javascript复制/// <summary>
///
/// </summary>
/// <param name="FileName">文件名称</param>
/// <param name="FilePath">文件路径</param>
public void DownLoad(string FileName, string FilePath)
{
string result = string.Empty;
WebClient wc = new WebClient();
wc.BaseAddress = FilePath;
byte[] bytes;
bytes = wc.DownloadData(wc.BaseAddress);
Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition", string.Format("attachment;filename={0}", HttpUtility.UrlEncode(
FileName), System.Text.Encoding.UTF8));
MemoryStream ms = new MemoryStream(bytes);
ms.WriteTo(Response.OutputStream);
ms.Dispose();
ms.Close();
}
方法四:
代码语言:javascript复制/// <summary>
/// 下载实时返回下载进度
/// </summary>
/// <param name="URL">下载地址</param>
/// <param name="filename">本地存储地址</param>
public void DownloadFileData2(string URL, string filename)
{
float percent = 0;
try
{
HttpWebRequest Myrq = (HttpWebRequest)HttpWebRequest.Create(URL);
HttpWebResponse myrp = (HttpWebResponse)Myrq.GetResponse();
long totalBytes = myrp.ContentLength, totalDownloadedByte = 0;
Stream st = myrp.GetResponseStream();
using (MemoryStream ms = new MemoryStream())
{
HttpResponse response = System.Web.HttpContext.Current.Response;
response.Clear();
response.Charset = "GB2312";
response.ContentType = "application/msword";
byte[] by = new byte[1024];
int osize = st.Read(by, 0, (int)by.Length);
while (osize > 0)
{
totalDownloadedByte = osize totalDownloadedByte;
ms.Write(by, 0, osize);
osize = st.Read(by, 0, (int)by.Length);
percent = (float)totalDownloadedByte / (float)totalBytes * 100;//当前位置
}
st.Close();
System.Web.HttpContext.Current.Response.AddHeader("Content-Disposition", string.Format("attachment; filename=" filename));
response.ContentEncoding = System.Text.Encoding.Unicode;
ms.WriteTo(response.OutputStream);
ms.Close();
}
HttpContext.Current.Response.End();
}
catch (System.Exception)
{
throw;
}
}
文件先保存在下载
代码语言:javascript复制//string fileName = DateTime.Now.ToString("yyyyMMddHHmmss") ".doc";
using (MemoryStream ms = new MemoryStream())
{
HttpResponse response = System.Web.HttpContext.Current.Response;
response.Clear();
response.Charset = "GB2312";
response.ContentType = "application/msword";
doc.Save(ms, SaveFormat.Doc);
System.Web.HttpContext.Current.Response.AddHeader("Content-Disposition", string.Format("attachment; filename=" filename));
response.ContentEncoding = System.Text.Encoding.Unicode;
ms.WriteTo(response.OutputStream);
ms.Close();
}
HttpContext.Current.Response.End();