在傳統的HTTP應用程式上傳檔案想要同時上傳多個檔案並查看上傳進度是一件很麻煩的事情,當然現在也有一些基於SWF的檔案上傳元件提供這種的便利性.到了HTML5下對文件的讀取和上傳的控制方面就非常靈活,HTML5提供一系列的AIP進行文件讀取,包括計取文件某一塊的內容也非常方便,結合Websocket進行文件的傳輸就變得更加方便和靈活.下面透過使用HTML5結合websocet簡單地實作多檔案同時上傳應用程式.
實作功能
大概預覽一下需要做的功能:
主要功能是使用者可以直接把資料夾的檔案直接拖放到網頁中,並進行上傳,在上傳的過程中顯示上傳進度資訊.
FileInfo類別封裝
為了方便讀取檔案資訊,在原有File的基礎封裝了一個簡單檔案資訊讀取的物件類別.
function FileInfo(file, pagesize) { this.Size = file.size; this.File = file; this.FileType = file.type; this.FileName = file.name; this.PageSize = pagesize; this.PageIndex = 0; this.Pages = 0; this.UploadError = null; this.UploadProcess = null; this.DataBuffer = null; this.UploadBytes = 0; this.ID = Math.floor(Math.random() * 0x10000).toString(16); this.LoadCallBack = null; if (Math.floor(this.Size % this.PageSize) > 0) { this.Pages = Math.floor((this.Size / this.PageSize)) + 1; } else { this.Pages = Math.floor(this.Size / this.PageSize); } } FileInfo.prototype.Reset = function () { this.PageIndex = 0; this.UploadBytes = 0; } FileInfo.prototype.toBase64String = function () { var binary = '' var bytes = new Uint8Array(this.DataBuffer) var len = bytes.byteLength; for (var i = 0; i < len; i++) { binary += String.fromCharCode(bytes[i]) } return window.btoa(binary); } FileInfo.prototype.OnLoadData = function (evt) { var obj = evt.target["tag"]; if (evt.target.readyState == FileReader.DONE) { obj.DataBuffer = evt.target.result; if (obj.LoadCallBack != null) obj.LoadCallBack(obj); } else { if (obj.UploadError != null) obj.UploadError(fi, evt.target.error); } } FileInfo.prototype.Load = function (completed) { this.LoadCallBack = completed; if (this.filereader == null || this.filereader == undefined) this.filereader = new FileReader(); var reader = this.filereader; reader["tag"] = this; reader.onloadend = this.OnLoadData; var count = this.Size - this.PageIndex * this.PageSize; if (count > this.PageSize) count = this.PageSize; this.UploadBytes += count; var blob = this.File.slice(this.PageIndex * this.PageSize, this.PageIndex * this.PageSize + count); reader.readAsArrayBuffer(blob); }; FileInfo.prototype.OnUploadData = function (file) { var channel = file._channel; var url = file._url; channel.Send({ url: url, parameters: { FileID: file.ID, PageIndex: file.PageIndex, Pages: file.Pages, Base64Data: file.toBase64String()} }, function (result) { if (result.status == null || result.status == undefined) { file.PageIndex++; if (file.UploadProcess != null) file.UploadProcess(file); if (file.PageIndex < file.Pages) { file.Load(file.OnUploadData); } } else { if (file.UploadError != null) file.UploadError(file, data.status); } }); } FileInfo.prototype.Upload = function (channel, url) { var fi = this; channel.Send({ url: url, parameters: { FileName: fi.FileName, Size: fi.Size, FileID: fi.ID} }, function (result) { if (result.status == null || result.status == undefined) { fi._channel = channel; fi._url = result.data; fi.Load(fi.OnUploadData); } else { if (file.UploadError != null) file.UploadError(fi, result.status); } }); }
類別的處理很簡單,透過file初始化並指定分塊大小來實始化一些檔案資訊,如頁數量頁大小等.當然最重要也封裝檔案對應的Upload方法,用來把檔案區塊訊息打包成base64訊息透過Websocket的方式傳送到伺服器.
檔案拖放
在HTML5中接受系統檔案拖放進來並不需要做複雜的事情,只需要針對容器元素綁定相關事件即可.
function onDragEnter(e) { e.stopPropagation(); e.preventDefault(); } function onDragOver(e) { e.stopPropagation(); e.preventDefault(); $(dropbox).addClass('rounded'); } function onDragLeave(e) { e.stopPropagation(); e.preventDefault(); $(dropbox).removeClass('rounded'); } function onDrop(e) { e.stopPropagation(); e.preventDefault(); $(dropbox).removeClass('rounded'); var readFileSize = 0; var files = e.dataTransfer.files; if (files.length > 0) { onFileOpen(files); } }
#只需要在onDrop過程中取得相關拖放檔案即可,這些可能透過一些HTML5的教程可以得到幫助。
這時候只需要針對選擇的檔案建構相關FileInfo物件,並呼叫上傳方法即可.
function onFileOpen(files) { if (files.length > 0) { for (var i = 0; i < files.length; i++) { var info = new FileInfo(files[i], 32768); uploads.push(info); info.UploadProcess = onUploadProcess; addUploadItem(info); } } }
透過UploadProcess事件對上傳檔案進度資訊進行一個設定更新
function onUploadProcess(file) { $('#p_' + file.ID).progressbar({ value: (file.PageIndex / file.Pages) * 100, text: file.FileName + '[' + file.UploadBytes + '/' + file.Size + ']' }); }
#C#服務端
借助Beetle對websocket的支援對應服務端的實作就非常簡單了
/// <summary> /// Copyright © henryfan 2012 ///CreateTime: 2012/12/14 21:13:34 /// </summary> public class Handler { public void UploadPackage(string FileID, int PageIndex, int Pages, string Base64Data) { Console.WriteLine("FileID:{2},PageIndex:{0} Pages:{1} DataLength:{3}", PageIndex, Pages, FileID,Base64Data.Length); } public string UploadFile(string FileID, string FileName, long Size) { Console.WriteLine("FileID:{2},FileName:{0} Size:{1}", FileName, Size, FileID); return "Handler.UploadPackage"; } }
服務端方法有兩個一個是上傳檔案請求,和一個上傳檔案區塊接收方法.
總結
只需要以上簡單的程式碼就能實現多檔案同時上傳功能,在這採用json來處理上傳的資訊,所以檔案流要進行一個base64的編碼處理,由於websocket瀏覽提交的資料一般都有MASK處理再加上base64那損耗相對來說比較重,實際上websocket有提供流的資料包格式(arraybuffer);當然這種處理在操作上就沒有json來得方便簡單.
下載程式碼:WebSocketUpload.rar
以上就是HTML5 WebSocket實作多檔案同時上傳的實例 的內容,更多相關內容請關注PHP中文網(www .php.cn)!