通常上传大文件都是把大的文件分割成几个小的组成部分来进行上传的。
客户端:
分割分件成几个单独的数据包并上传
服务端:
把单独的数据包组合成文件
这样可以使上传大的文件时不会一直占用网络资源,并且如可以的话还可以实现断点续传。
要想实现这种方法,这就要求客户端可以对文件进行二进制流的操作,
但是Javascript出于安全方面的并没有提供对二进制文件的操作。
不过,还好有Axtive控件,如果你觉得用Axtive控件不安全的话,那你还是别看这编了。
出于某些原因我写的客户端用了JQUERY框架,
还有就是客户端使用了ADODB.Stream,如果你禁用了这个的话你是没办法调试成功的。
首先我们来看看客户端:
每个块的结构为一个XML对象:
文件名
总大小
块大小
内容
<script type="text/javascript">
var modSize,pageNum,curUpID,curUpSize;
var fileName,totalSize,sizePerBlock,url;
var stream = new ActiveXObject("ADODB.Stream");
function SendFile(pathName,tmpSizePerBlock,tmpUrl)//我们只要调用这个就可以发送文件了
{ //第一个参数是文件路径
UpStartInit(pathName,tmpSizePerBlock,tmpUrl); //第二个参数是文件要被分成的块大小
if(pageNum==0) //第三个参数是发送的URL地址
{
UploadDirect();
}
else
{
if(modSize==0)
{
UploadNot();
}
else
{
UploadMod();
}
}
}
function UpStartInit(pathName,tmpSizePerBlock,tmpUrl)
{
fileName=getFileName(pathName);
curUpID=0;
curUpSize=tmpSizePerBlock;
sizePerBlock=tmpSizePerBlock;
url=tmpUrl;
stream.Open();
stream.Type=1;
stream.LoadFromFile(pathName);
pageNum=parseInt(stream.Size/1000);
modSize=stream.Size%1000;
}
function getFileName(filePath)
{
var pos = filePath.lastIndexOf(//)*1;
return filePath.substring(pos+1);
}
function UploadDirect()
{
var content=UpFileEncoding(fileName,stream.Size,stream.Size,stream);
$.ajax({
url: url,
processData: false,
data: content,
success:function(xml){
UploadFinish();
}
});
}
function UploadNot()
{
var content=UpFileEncoding(fileName,stream.Size,curUpSize,stream);
$.ajax({
url: url,
processData: false,
data: content,
success:function(xml){
UploadCallback();
}
});
}
function UploadMod()
{
var content=UpFileEncoding(fileName,stream.Size,curUpSize,stream);
$.ajax({
url: url,
processData: false,
data: content,
success:function(xml){
UploadCallback2();
}
});
}
function UploadCallback()
{
curUpID++;
curUpSize=sizePerBlock;
if(curUpID==pageNum)
{
FinishInit();
}
else
{
UploadNotDirect();
}
}
function UploadCallback2()
{
curUpID++;
if(curUpID==(pageNum-1))
{
curUpSize=sizePerBlock+modSize;
}
else
{
curUpSize=sizePerBlock;
}
if(curUpID==pageNum)
{
FinishInit();
}
else
{
UploadMod();
}
}
function UploadFinish()
{
FinishInit();
}
function FinishInit()
{
stream.Close();
alert("完成!");
}
function UpFileEncoding(paramFileName,paramTotalSize,paramBlockSize,paramStream)
{
var xml_dom=new ActiveXObject("Msxml2.DOMDocument");
xml_dom.loadXML('<?xml version="1.0" ?><root/>');
xml_dom.documentElement.setAttribute("xmlns:dt","urn:schemas-microsoft-com:datatypes");
var l_node1=xml_dom.createElement("FileName");
var l_node2=xml_dom.createElement("TotalSize");
var l_node3=xml_dom.createElement("BlockSize");
var l_node4=xml_dom.createElement("PartContent");
l_node1.text=paramFileName;
l_node2.text=paramTotalSize;
l_node3.text=paramBlockSize;
xml_dom.documentElement.appendChild(l_node1);
xml_dom.documentElement.appendChild(l_node2);
xml_dom.documentElement.appendChild(l_node3);
l_node4.dataType=="bin.base64";
l_node4.text=paramStream.Read(paramBlockSize);
xml_dom.documentElement.appendChild(l_node4);
return xml_dom;
}
</script>
再来看下服务端的代码(C#的):
在服务端只要使用
HWUpload.ReceiveData();接收数据
HWUpload.SaveToFile("E://");保存文件到指定目录
using System;
using System.Data;
using System.Web;
using System.Web.Caching;
using System.Xml;
using System.IO;
/// <summary>
/// HWUpload 的摘要说明
/// </summary>
public class HWUpload
{
public static HWUploadInfo GetCurUploadInfo()
{
if (HttpContext.Current.Session["CurUpload"] == null)
{
return null;
}
else
{
return (HWUploadInfo)HttpContext.Current.Session["CurUpload"];
}
}
public static bool IsUploadFile(string fileName)
{
HWUploadInfo tmpinfo = GetCurUploadInfo();
if (tmpinfo!=null)
{
if (tmpinfo.FileName == fileName)
{
return true;
}
}
return false;
}
public static string GetCurFileName()
{
return GetCurUploadInfo().FileName;
}
public static byte[] GetCurData()
{
return GetCurUploadInfo().Data;
}
public static int GetCurSize()
{
return GetCurUploadInfo().CurSize;
}
public static bool AddCurSize(int blockSize)
{
GetCurUploadInfo().CurSize += blockSize;
return true;
}
public static bool SetCurUploadInfo(HWUploadInfo uploadInfo)
{
HttpContext.Current.Session["CurUpload"] = uploadInfo;
return true;
}
public static bool AddCurData(byte[] data, int size)
{
MemoryStream tmpstream = new MemoryStream();
tmpstream.Write(GetCurData(), 0, GetCurSize());
tmpstream.Write(data, 0, size);
tmpstream.Close();
GetCurUploadInfo().Data = tmpstream.ToArray();
AddCurSize(size);
return true;
}
public static void ReceiveData()
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(HttpContext.Current.Request.InputStream);
byte[] content = Convert.FromBase64String(xmlDoc.DocumentElement.SelectSingleNode("PartContent").InnerXml);
string fileName = xmlDoc.DocumentElement.SelectSingleNode("FileName").InnerXml;
int totalSize = Convert.ToInt32(xmlDoc.DocumentElement.SelectSingleNode("TotalSize").InnerXml);
int blockSize = Convert.ToInt32(xmlDoc.DocumentElement.SelectSingleNode("BlockSize").InnerXml);
if (IsUploadFile(fileName))
{
AddCurData(content, blockSize);
}
else
{
HWUploadInfo uploadInfo = new HWUploadInfo();
uploadInfo.FileName = fileName;
uploadInfo.TotalSize = totalSize;
uploadInfo.CurSize = blockSize;
uploadInfo.Data = content;
SetCurUploadInfo(uploadInfo);
}
}
public static bool IsFinish()
{
if(GetCurUploadInfo().CurSize==GetCurUploadInfo().TotalSize)
{
return true;
}
else
{
return false;
}
}
public static void SaveToFile(string path)
{
if (IsFinish())
{
FileStream fileStream = new FileStream(path + "//" + GetCurFileName(), FileMode.Create);
fileStream.Write(GetCurData(), 0, GetCurSize());
fileStream.Close();
SetCurUploadInfo(null);
}
}
}
public class HWUploadInfo
{
private string m_fileName;
private int m_curSize;
private int m_totalSize;
private byte[] m_data;
public string FileName
{
get
{
return m_fileName;
}
set
{
m_fileName = value;
}
}
public int CurSize
{
get
{
return m_curSize;
}
set
{
m_curSize = value;
}
}
public int TotalSize
{
get
{
return m_totalSize;
}
set
{
m_totalSize = value;
}
}
public byte[] Data
{
get
{
return m_data;
}
set
{
m_data = value;
}
}
}
现在要告诉大家两个不好的消息:
1、这个只能单文件上传
2、以上代码由于某些原因还没测试(如果哪有误,请误怪,因为思路是正确的)
不过如果我完成测试后一定会很快传上来的。