使用Html5的WebSocket在瀏覽器上傳文件, 支持多文件和大文件.


使用websocket上傳文件的簡單例子: 使用Html5的WebSocket在瀏覽器上傳文件

上篇文章沒有解決的問題就是大文件的上傳問題, 而且多文件上傳問題也未協調. 所以這篇文章就是解決這兩個問題的.

如果將一個大文件直接讀入內存再發送的話, 內存會吃不消, 所以我們把大文件分塊傳輸.  Html5的Fileread方法提供了讀取文件部分內容Blob的方法.

為了保證后台接收到的分塊數據的順序不會亂掉, 我們需要后台確定寫入分塊數據后再發送下一塊數據. 

在Html端:

<!DOCTYPE html>
<html>
<head>
<title>WebSocket Chat Client</title>
<meta charset="utf-8" />
<script type="text/javascript" src="jquery-1.6.4.min.js"></script>
<script type="text/javascript" src="jquery.json-2.3.min.js"></script>
<script type="text/javascript">
$().ready(
function() {
// Check for the various File API support.
              if (window.File && window.FileReader && window.FileList
&& window.Blob) {
// Great success! All the File APIs are supported.
} else {
alert(
'The File APIs are not fully supported in this browser.');
}
});

//在消息框中打印內容
function log(text) {
$(
"#log").append(text+"\n");
}

//全局的websocket變量
var ws;
var paragraph = 10485760;
var fileList ;
var file;
var startSize,endSize = 0;
var i = 0; j = 0;
//連接服務器
$(function() {
$(
"#connect").click(function() {
ws
= new WebSocket($("#uri").val());
//連接成功建立后響應
ws.onopen = function() {
log(
"成功連接到" + $("#uri").val());
}
//收到服務器消息后響應
ws.onmessage = function(e) {
log(
"服務器說" + e.data + (e.data=="ok"));
if(e.data == "ok"){
if(endSize < file.size){
startSize
= endSize;
endSize
+= paragraph ;
if (file.webkitSlice) {
var blob = file.webkitSlice(startSize, endSize);
}
else if (file.mozSlice) {
var blob = file.mozSlice(startSize, endSize);
}
var reader = new FileReader();
reader.readAsArrayBuffer(blob);
reader.onload
= function loaded(evt) {
var ArrayBuffer = evt.target.result;
log(
"發送文件第" + (i++) + "部分");
ws.send(ArrayBuffer);
}
}
else{
startSize
= endSize = 0;
i
= 0;
log(
"發送" + file.name +"完畢");
file
= fileList[j++];
if(file.name){
ws.send(file.name);
}
log(
"發送文件完畢");
}
}
//連接關閉后響應
ws.onclose = function() {
log(
"關閉連接");
ws
= null;
}
return false;
}
});
});


$(
function() {
$(
"#sendFileForm").click(function() {
fileList
= document.getElementById("file").files;
file
= fileList[0];
ws.send(file.name);
})
});

$(
function() {
$(
"#reset").click(function() {
$(
"#log").empty();
return false;
});
});

</script>
</head>
<body>
<span>Html5功能測試</span>
<span id="progress">0</span><br>
<input type="text" id="uri" value="ws://localhost:8887"
style
="width: 200px;"> <input type="button" id="connect"
value
="Connect"><input type="button" id="disconnect"
value
="Disconnect" disabled="disabled">
<form >
<input id="file" type="file" multiple />
<input type="button" id="sendFileForm" value="測試" />
<input type="button" id="reset" value="清空消息框" />
</form>
<form>
<textarea id="log" rows="30" cols="100"
style
="font-family: monospace; color: red;"></textarea>
</form>
</body>
</html>

這里設置了文件大於paragraph (10M)時就會分塊發送文件.


服務器端:

/**
* 處理字符串消息
*/
public void onMessage( WebSocket conn, String message ) {

System.out.println("文件名" + message);
//將文件名寫入連接對象中,(需要手動修改webSocket類)
conn.setFileName(message);

try {
conn.send("ok");
} catch (NotYetConnectedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 處理二進制消息
*/
public void onMessage(WebSocket conn, byte[] message) {
System.out.println("收到二進制流:");
//將二進制流保存為文件, 文件名從連接對象中取出
saveFileFromBytes(message, "src/" + conn.getFileName());
//告訴前台可以繼續發送了.
try {
conn.send("ok");
} catch (NotYetConnectedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

/**
* 將二進制byte[]數組寫入文件中
*
@param b byte[]數組
*
@param outputFile 文件位置
*
@return 成功: true 失敗: false
*/
public static boolean saveFileFromBytes(byte[] b, String outputFile)
{
FileOutputStream fstream = null;
File file = null;
try
{
file = new File(outputFile);
fstream = new FileOutputStream(file, true);
fstream.write(b);
}
catch (Exception e)
{
e.printStackTrace();
return false;
}
finally
{
if (fstream != null)
{
try
{
fstream.close();
}
catch (IOException e1)
{
e1.printStackTrace();
}
}
}
return true;
}


好了, 順序發送保證了后台寫入的數據也是順序的, 文件就不會出錯了! 搞定!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM