前端使用js分片上传大文件代码
//注,js脚本可写在一个js文件里面,这样显得代码看起来简洁
<script>
var BYTES_PER_CHUNK = 1024 * 1024;//计算每个文件切割的大小-->1M
var slices;//切割文件的总数
var totalslices;//切割文件的总数
var xhr;//待赋值XMLHttpRequest对象
var start = 0;
var end;
var index = 0;
var blob;
var tagfilename;
var oloaded = 0;
function sendRequest() {
blob = document.getElementById("file").files[0];//获取第一个文件对象
start = 0;//切割文件的起始大小
end;//切割文件的结束大小
index = 0;
tagfilename = "";
ot = new Date().getTime(); //设置上传开始时间
oloaded = 0;//设置上传开始时,以上传的文件大小为0
slices = Math.ceil(blob.size / BYTES_PER_CHUNK);//
totalslices = slices;
end = start + BYTES_PER_CHUNK;
if (end > blob.size) {
end = blob.size;
}
uploadFile(blob, index, start, end);
};
function uploadFile(blob, index, start, end) {
var fd;
var chunk;
var sliceindex = blob.name + "@@" + index;
chunk = blob.slice(start, end);//切割文件,切割文件范围为start-end
fd = new FormData();//表单形式的格式化
/*****上传参数************/
fd.append("UpgradeFileName", chunk, sliceindex);//服务器存储的文件名
fd.append("totalslices", slices);//分割文件的总个数
fd.append("totalsize", blob.size);//文件总的大小
fd.append("tagfilename", tagfilename);
fd.append("filesindex", index + 1);
/*****上传参数************/
xhr = new XMLHttpRequest();//新建XMLhttpRequest对象
xhr.open("POST", "Handler1.ashx?action=uploadfile", true);//异步上传,同步上传会阻塞UI线程
xhr.upload.onprogress = progressFunction;//【上传进度调用方法实现】,跨域时,则取消该方法即可
xhr.onload = uploadCompete;//请求完成回调方法
xhr.onerror = uploadFailed;//请求失败回调方法
xhr.send(fd);//发送
};
//单个文件上传成功回调方法
function uploadCompete(evt) {
var data = eval('(' + evt.target.responseText + ')');//evt.target.responseText为json格式字符串,使用eval方法获取
tagfilename = data.tagfilename;//回去上传到服务器文件的新的服务器存储的文件名
console.log(data.tagfilename);//输出到控制台,供调试查看
start = end;
index++;//子文件上传成功,index加1,用于判断文件是否上传结束
end = start + BYTES_PER_CHUNK;
if (end > blob.size) {
end = blob.size;
}
if (index < totalslices) {//当上传文件个数小于总个数时,继续上传下一个文件
uploadFile(blob, index, start, end);
}
if (index >= totalslices) {
alert("文件上传成功");
var percentageDiv = document.getElementById("percentage");
percentageDiv.innerHTML = "100% 文件上传成功";
}
};
//单个文件上传失败的回调方法
function uploadFailed(evt) {
uploadFile(blob, index, start, end);
};
//取消上传
function cancleUploadFile(){
xhr.abort();
};
//上传进度实现方法,上传过程中会频繁调用该方法,在进行跨域上传时,需要配置远程服务器端和客户端界面,取消该方法则不会涉及到跨域问题。
function progressFunction(evt) {
var progressBar = document.getElementById("progressBar");
var percentageDiv = document.getElementById("percentage");
// event.total是需要传输的总字节,event.loaded是已经传输的字节。如果event.lengthComputable不为真,则event.total等于0
if (evt.lengthComputable) {
progressBar.max = blob.size;
progressBar.value = start + evt.loaded;
if ((start + evt.loaded)/blob.size>=1)
{
percentageDiv.innerHTML = "100% 请稍后,正在处理。。";
}else
{
percentageDiv.innerHTML = Math.round((start+evt.loaded) / blob.size * 100) + "%";
}
}
var time = document.getElementById("time");
var nt = new Date().getTime();//获取当前时间
if (nt - ot >= 1000) {
var pertime = (nt-ot)/1000; //计算出上次调用该方法时到现在的时间差,单位为s
ot = new Date().getTime(); //重新赋值时间,用于下次计算
var perload = start+ evt.loaded - oloaded; //计算该分段上传的文件大小,单位b
oloaded = start+ evt.loaded;//重新赋值已上传文件大小,用以下次计算
//上传速度计算
var speed = perload/pertime;//单位b/s
var bspeed = speed;
var units = 'b/s';//单位名称
if(speed/1024>1){
speed = speed/1024;
units = 'k/s';
}
if(speed/1024>1){
speed = speed/1024;
units = 'M/s';
}
speed = speed.toFixed(1);
//剩余时间
var resttime = ((blob.size-start-evt.loaded)/bspeed).toFixed(1);
time.innerHTML = '文件上传速度:' + speed + units + ',剩余时间:' + resttime + 's';
}
if(bspeed==0) time.innerHTML = '上传已取消';
};
</script>
<body>
<form id="form1" runat="server">
<div>
<div class="page-header">
<h1>上传文件
<small>...</small>
</h1>
</div>
<div class="content">
<table >
<tbody>
<tr>
<th colspan="2"><input type="file" id="file" name="myfile" style="font-size:20px ;width:30rem" class="btn btn-upload"/></th>
<th class="auto-style1"><input type="button" id="uploadfile" class="btn btn-upload" onclick="sendRequest()" value="上传" style="font-size:30px;margin-left:1rem;"/></th>
</tr>
<tr>
<th colspan="2" >
<progress id="progressBar" value="0" max="100" style="width:30rem;margin-top:1rem;"></progress>
<span id="percentage"></span></th>
<th class="auto-style1"><input type="button" id="btntest" onclick="cancleUploadFile()" class="btn btn-upload" value="取消" style="font-size:30px;margin-left:1rem;margin-top:1rem;"/></th>
</tr>
<tr>
<th colspan="3">
<span id="time" style="font-size:20px"></span>
</th>
</tr>
</tbody>
</table>
</div>
</div>
</form>
</body>
前端界面显示:
C# ASP.net后端文件处理代码
代码使用一般处理文件完成 Handler1.ashx
//注:文件合并没想出其他好方法,像浏览器下载的文件,都只生成一个,在一个文件上进行读写
public void ProcessRequest(HttpContext context)
{
if(context.Request.QueryString["action"]!=null && context.Request.QueryString["action"].ToString()=="uploadfile")
{
string tagfilename = "";
if(context.Request.Form["tagfilename"]==null || context.Request.Form["tagfilename"]=="")
{
tagfilename = Guid.NewGuid().ToString();
}
else
{
tagfilename = context.Request.Form["tagfilename"].ToString();
}
var file = context.Request.Files[0];
int oldmin = file.FileName.LastIndexOf("\\");
int oldmax = file.FileName.Length;
string oldfilename="";
if (oldmin<0)
{
oldfilename = file.FileName;
}
else
{
oldfilename = file.FileName.Substring(oldmin+2, oldmax - oldmin-2);
}
string newName = tagfilename + oldfilename;
file.SaveAs(@"c:\files\" + newName);
if(context.Request.Form["totalslices"] != null && context.Request.Form["filesindex"] != null && context.Request.Form["totalslices"] == context.Request.Form["filesindex"])
{
int count = newName.LastIndexOf("@@");
int index =Convert.ToInt16(context.Request.Form["filesindex"]);
string eachname = newName.Substring(0, count);
string[] fileIn=new string[index];
for(int i=0;i<index;i++)
{
fileIn[i] = @"c:\files\" + eachname + "@@" + i.ToString();
}
fileCombine(fileIn, true, 1);
}
context.Response.Write("{\"success\":1,\"tagfilename\":\""+ tagfilename + "\"}");
}
}
/// <summary>
/// 文件合并函数,
/// 可将任意个子文件合并为一个,为fileSplit()的逆过程
/// delet标识是否删除原文件, change对data的首字节进行解密
/// </summary>
public void fileCombine(String[] fileIn, bool delet, int change)
{
//输入文件名校验
if (fileIn == null || fileIn.Length == 0) return;
string name = fileIn[0];
int i1 = name.LastIndexOf("@@");//name.LastIndexOf('.');
int i2 = name.Length;
name = name.Substring(0, i1); //剔除子文件拓展名".split"
//string fileOut = (i1 == -1) ? name : name.Remove(i1, i2 - i1); //剔除"@_1" -> "D:\\1.rar.split"
//创建输出文件,已有则覆盖
FileStream FileOut = new FileStream(name, FileMode.Create);
for (int i = 0; i < fileIn.Length; i++)
{
//输入文件校验
if (fileIn[i] == null || !System.IO.File.Exists(fileIn[i])) continue;
//从子文件创建输入流
FileStream FileIn = new FileStream(fileIn[i], FileMode.Open);
byte[] data = new byte[1024]; //流读取,缓存空间
int readLen = 0; //每次实际读取的字节大小
while ((readLen = FileIn.Read(data, 0, data.Length)) > 0) //读取数据
{
//输出,缓存数据写入文件
FileOut.Write(data, 0, readLen);
FileOut.Flush();
}
//关闭输入流,删除源文件
FileIn.Close();
if (delet) System.IO.File.Delete(fileIn[i]);
}
FileOut.Close(); //关闭输出流
}
上传效果