通常上傳大文件都是把大的文件分割成幾個小的組成部分來進行上傳的。
客戶端:
分割分件成幾個單獨的數據包並上傳
服務端:
把單獨的數據包組合成文件
這樣可以使上傳大的文件時不會一直佔用網絡資源,並且如可以的話還可以實現斷點續傳。
要想實現這種方法,這就要求客戶端可以對文件進行二進制流的操作,
但是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、以上代碼由於某些原因還沒測試(如果哪有誤,請誤怪,因爲思路是正確的)
不過如果我完成測試後一定會很快傳上來的。