HTML5 - WebSocket實現多文件同時上傳


在傳統的HTTP應用上傳文件想要同時上傳多個文件並查看上傳進度是一件很麻煩的事情,固然如今也有一些基於SWF的文件上傳組件提供這種的便利性.到了HTML5下對文件的讀取和上傳的控制方面就很是靈活,HTML5提供一系列的AIP進行文件讀取,包括計取文件某一塊的內容也很是方便,結合Websocket進行文件的傳輸就變得更加方便和靈活.下面經過使用HTML5結合websocet簡單地實現多文件同時上傳應用. html

實現功能

大概預覽一下須要作的功能: html5

主要功能是用戶能夠直接把文件夾的文件直接拖放到網頁中,並進行上傳,在上傳的過程當中顯示上傳進度信息. web

FileInfo類封裝

爲了方便讀取文件信息,在原有File的基礎封裝了一個簡單文件信息讀取的對象類. chrome

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
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的方式發送到服務器. json

文件拖放

在HTML5中接受系統文件拖放進來並不須要作複雜的事情,只須要針對容器元素綁定相關事件便可. 瀏覽器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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的教程能夠獲得幫助,詳細看http://www.html5rocks.com/zh/tutorials/file/dndfiles/ 服務器

這時候只須要針對選擇的文件構建相關FileInfo對象,並調用上傳方法便可. websocket

1
2
3
4
5
6
7
8
9
10
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事件對上傳文件進度信息進行一個設置更新 dom

1
2
3
4
5
function onUploadProcess(file) {
            $('#p_' + file.ID).progressbar({ value: (file.PageIndex / file.Pages) * 100,
                text: file.FileName +'[' + file.UploadBytes +'/' + file.Size +']'
            });
        }

C#服務端

藉助於Beetle對websocket的支持對應服務端的實現就很是簡單了 socket

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/// <summary>
    /// Copyright © henryfan 2012       
    ///Email:   henryfan@msn.com   
    ///HomePage:    http://www.ikende.com      
    ///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 (642.65 kb) 

演示地址:http://html5.ikende.com/upload.htm 使用chrome或IE10瀏覽器

原文:http://www.cnblogs.com/smark/archive/2012/12/17/2822487.html
相關文章
相關標籤/搜索