asp.net 文件下载实现代码
程序员文章站
2024-03-08 19:22:52
复制代码 代码如下:public static bool downloadfile(httpcontext httpcontext, string filepath, lo...
复制代码 代码如下:
public static bool downloadfile(httpcontext httpcontext, string filepath, long speed)
{
bool ret = true;
try
{
#region--验证:httpmethod,请求的文件是否存在
switch (httpcontext.request.httpmethod.toupper())
{ //目前只支持get和head方法
case "get":
case "head":
break;
default:
httpcontext.response.statuscode = 501;
return false;
}
if (!file.exists(filepath))
{
httpcontext.response.statuscode = 404;
return false;
}
#endregion
#region 定义局部变量
long startbytes = 0;
int packsize = 1024 * 10; //分块读取,每块10k bytes
string filename = path.getfilename(filepath);
filestream myfile = new filestream(filepath, filemode.open, fileaccess.read, fileshare.readwrite);
binaryreader br = new binaryreader(myfile);
long filelength = myfile.length;
int sleep = (int)math.ceiling(1000.0 * packsize / speed);//毫秒数:读取下一数据块的时间间隔
string lastupdatetiemstr = file.getlastwritetimeutc(filepath).tostring("r");
string etag = httputility.urlencode(filename, encoding.utf8) + lastupdatetiemstr;//便于恢复下载时提取请求头;
#endregion
#region--验证:文件是否太大,是否是续传,且在上次被请求的日期之后是否被修
if (myfile.length > int32.maxvalue)
{//-------文件太大了-------
httpcontext.response.statuscode = 413;//请求实体太大
return false;
}
if (httpcontext.request.headers["if-range"] != null)//对应响应头etag:文件名+文件最后修改时间
{
//----------上次被请求的日期之后被修改过--------------
if (httpcontext.request.headers["if-range"].replace("\"", "") != etag)
{//文件修改过
httpcontext.response.statuscode = 412;//预处理失败
return false;
}
}
#endregion
try
{
#region -------添加重要响应头、解析请求头、相关验证-------------------
httpcontext.response.clear();
httpcontext.response.buffer = false;
httpcontext.response.addheader("content-md5", getmd5hash(myfile));//用于验证文件
httpcontext.response.addheader("accept-ranges", "bytes");//重要:续传必须
httpcontext.response.appendheader("etag", "\"" + etag + "\"");//重要:续传必须
httpcontext.response.appendheader("last-modified", lastupdatetiemstr);//把最后修改日期写入响应
httpcontext.response.contenttype = "application/octet-stream";//mime类型:匹配任意文件类型
httpcontext.response.addheader("content-disposition", "attachment;filename=" + httputility.urlencode(filename, encoding.utf8).replace("+", "%20"));
httpcontext.response.addheader("content-length", (filelength - startbytes).tostring());
httpcontext.response.addheader("connection", "keep-alive");
httpcontext.response.contentencoding = encoding.utf8;
if (httpcontext.request.headers["range"] != null)
{//------如果是续传请求,则获取续传的起始位置,即已经下载到客户端的字节数------
httpcontext.response.statuscode = 206;//重要:续传必须,表示局部范围响应。初始下载时默认为200
string[] range = httpcontext.request.headers["range"].split(new char[] { '=', '-' });//"bytes=1474560-"
startbytes = convert.toint64(range[1]);//已经下载的字节数,即本次下载的开始位置
if (startbytes < 0 || startbytes >= filelength)
{//无效的起始位置
return false;
}
}
if (startbytes > 0)
{//------如果是续传请求,告诉客户端本次的开始字节数,总长度,以便客户端将续传数据追加到startbytes位置后----------
httpcontext.response.addheader("content-range", string.format(" bytes {0}-{1}/{2}", startbytes, filelength - 1, filelength));
}
#endregion
#region -------向客户端发送数据块-------------------
br.basestream.seek(startbytes, seekorigin.begin);
int maxcount = (int)math.ceiling((filelength - startbytes + 0.0) / packsize);//分块下载,剩余部分可分成的块数
for (int i = 0; i < maxcount && httpcontext.response.isclientconnected; i++)
{//客户端中断连接,则暂停
httpcontext.response.binarywrite(br.readbytes(packsize));
httpcontext.response.flush();
if (sleep > 1) thread.sleep(sleep);
}
#endregion
}
catch
{
ret = false;
}
finally
{
br.close();
myfile.close();
}
}
catch
{
ret = false;
}
return ret;
}