HTML 5 断点续上传

         断点上传,java里面比较靠谱一点的,通常都会选用Flex。我认可,Flex只是摸了一下,不精通。HTML 5 有个Blob对象(File对象继承它),这个对象有个方法slice方法,能够对一个文件进行分片。基于前些日子写的《WebSocket的服务端实现》,再加上HTML 5的File API(可参考:HTML5中的文件处理 之 File API,或者W3C File API)和WebStorage。作了一个段断点续传的demo。javascript

        代码比较挫,把一个文件分红一个个小片以后,每一次上传都会将已经上传的字节数放到LocalStorage里面。关于LocalStorage里面缓存怎么清,能够参看Chrome - HTML 5 本地存储。若是上传的途中暂停或者直接关掉浏览器。下次上传的时候,就会从那个节点开始上传。html

PS:demo操做,请先创建WS链接以后,再选择文件上传html5

代码请笑纳java

<!DOCTYPE html>
<html>
<head>
    <title>使用WebSocket实现断点续传文件</title>
	<meta charset="utf-8">
</head>
<script type="text/javascript" src="demo.js"></script>

<body onload="init();">
<button onclick="webSocketConn();">建立链接</button>(step1)
<div class="row">
      <label for="fileToUpload">Select a File to Upload</label>
	  <input type="file" name="fileToUpload" id="fileToUpload" onchange="fileSelected();"/>(step2)
</div>
<div id="fileName"></div>
<div id="fileSize"></div>
<div id="fileType"></div>
<div class="row">
	<button onclick="sendFileName();uploadFile()">上传</button>(step3)
	<button onclick="pauseUpload()">暂停</button>
	&nbsp;<label id="progressNumber"></label>
</div>
<div id="msg" style="max-height: 400px; overflow:auto;min-height: 100px;">
</div>
</body>
</html>


#######  断点续传  ######
author:linrb
createTime: 2012-08-22
QQ: 569830404
*/
var websocket = null;  //websocket
var msg = null; //日志
var paragraph = 10240;  //每次分片传输文件的大小 10KB
var blob = null;//  分片数据的载体Blob对象
var file = null; //传输的文件
var startSize,endSize = 0; //分片的始终字节点
var uploadState = 0;  // 0: 无上传/取消, 1: 上传中, 2: 暂停

//初始化消息框
function init(){
	msg = document.getElementById("msg");
}
/**
 * 分片上传文件
 */
function uploadFile() {
	if(file){
		//将上传状态设置成1
		uploadState = 1;
		endSize = getLastestUploadEndSize(file);
		var reader = new FileReader();
		reader.onload = function loaded(evt) {
			var ArrayBuffer = evt.target.result;
			websocket.send(ArrayBuffer);
			uploadProgress(endSize);
		};
		if(endSize < file.size){
			//先发送文件名称
			//websocket.send(file.name);
			//处理文件发送(字节)
	        startSize = endSize;
	        if(paragraph > (file.size - endSize)){
	        	endSize = file.size;
	        }else{
	        	endSize += paragraph ;
	        }
	        if (file.webkitSlice) {
    		  //webkit浏览器
	        	blob = file.webkitSlice(startSize, endSize);
	        }else 
	        	blob = file.slice(startSize, endSize);
	        reader.readAsArrayBuffer(blob);
	    }
	}
}

//显示处理进程
function uploadProgress(uploadLen) {
    var percentComplete = Math.round(uploadLen * 100 / file.size);
    document.getElementById('progressNumber').innerHTML = percentComplete.toString() + '%';

    //保存到LocalStorage一边下次传输,能够记忆起这个断点
    localStorage.setItem(file.lastModifiedDate + "_" + file.name, uploadLen);
    
}

//WebSocket链接
function webSocketConn(){
	try{
		var readyState = new Array("正在链接", "已创建链接", "正在关闭链接"
					, "已关闭链接");
		var host = "ws://localhost:8000";
		websocket = new WebSocket(host);
		websocket.onopen = function(){
			msg.innerHTML += "<p>Socket状态: " + readyState[websocket.readyState] + "</p>";
		};
		websocket.onmessage = function(event){
			//每上传一个分片以后,等待介绍了服务端的提示以后再作下一个分片上传
			if(event.data.indexOf("ok") != -1 && uploadState == 1){
				if(endSize == file.size){
					localStorage.removeItem(file.lastModifiedDate + "_" + file.name);
					msg.innerHTML += "<p>上传完成!!</p>";
					websocket.close();//结束上传
				}else{
					uploadFile();
				}
			}
		};
		websocket.onclose = function(){
			msg.innerHTML += "<p>Socket状态: " + readyState[websocket.readyState] + "</p>";
		};
		msg.innerHTML += "<p>Socket状态: " + readyState[websocket.readyState] + "</p>";
	}catch(exception){
		msg.innerHTML += "<p>有错误发生</p>";
		return;
	}
}

/*
暂停上传
*/
function pauseUpload(){
	uploadState = 2;
}

/**
 * 从localStorage检查最后一次上传的字节
 */
function getLastestUploadEndSize(uploadFile){
	var lastestLen = localStorage.getItem(uploadFile.lastModifiedDate + "_" + uploadFile.name);
	if(lastestLen){
		return parseInt(lastestLen);
	}else{
		return 0;
	}
}


/*
	发送文件名
*/
function sendFileName(){
	websocket.send(file.name);
}
/**
 * 选择文件以后触发事件
 */
function fileSelected() {
  file = document.getElementById('fileToUpload').files[0];
  if (file) {
    var fileSize = 0;
    if (file.size > 1024 * 1024)
      fileSize = (Math.round(file.size * 100 / (1024 * 1024)) / 100).toString() + 'MB';
    else
      fileSize = (Math.round(file.size * 100 / 1024) / 100).toString() + 'KB';

    document.getElementById('fileName').innerHTML = 'Name: ' + file.name;
    document.getElementById('fileSize').innerHTML = 'Size: ' + fileSize;
    document.getElementById('fileType').innerHTML = 'Type: ' + file.type;
  }
}

服务端:web

package fileUpload;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.security.MessageDigest;



public class UploadServer {
	private int port = 8000;
	private ServerSocket serverSocket;

	public UploadServer() throws IOException {
		serverSocket = new ServerSocket(port);
		System.out.println("服务器启动");
	}

	private void service() {
		Socket socket = null;
		while (true) {
			try {
				socket = serverSocket.accept();
				Thread workThread = new Thread(new Handler(socket));
				workThread.start();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	class Handler implements Runnable {
		private Socket socket;
		private boolean hasHandshake = false;
		Charset charset = Charset.forName("UTF-8");  
		private File file = null;
		private FileOutputStream fileOut = null;
		
		public Handler(Socket socket) {
			this.socket = socket;
		}

		private PrintWriter getWriter(Socket socket) throws IOException {
			OutputStream socketOut = socket.getOutputStream();
			return new PrintWriter(socketOut, true);
		}


		public String echo(String msg) {
			return "echo:" + msg;
		}

		public void run() {
			
			try {
				System.out.println("New connection accepted"
						+ socket.getInetAddress() + ":" + socket.getPort());
				InputStream in = socket.getInputStream();
			    
				PrintWriter pw = getWriter(socket);
				//读入缓存
				byte[] buf = new byte[1024];
				//读到字节
				int len = in.read(buf, 0, 1024);
				//读到字节数组
				byte[] res = new byte[len];
				System.arraycopy(buf, 0, res, 0, len);
				String key = new String(res);
				if(!hasHandshake && key.indexOf("Key") > 0){
					key = key.substring(0, key.indexOf("==") + 2);
					key = key.substring(key.indexOf("Key") + 4, key.length()).trim();
					key+= "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
					MessageDigest md = MessageDigest.getInstance("SHA-1");  
					md.update(key.getBytes("utf-8"), 0, key.length());
					byte[] sha1Hash = md.digest();  
				        sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder();  
					key = encoder.encode(sha1Hash);  
					pw.println("HTTP/1.1 101 Switching Protocols");
					pw.println("Upgrade: websocket");
					pw.println("Connection: Upgrade");
					pw.println("Sec-WebSocket-Accept: " + key);
					pw.println();
					pw.flush();
					hasHandshake = true;
					
					//接收数据
					byte[] first = new byte[1];
				        int read = in.read(first, 0, 1);
				        while(read > 0){
				        	int b = first[0] & 0xFF;
				            //boolean fin = (b & 0x80) > 0;
				           // int rsv = (b & 0x70) >>> 4;
				            byte opCode = (byte) (b & 0x0F);
				            
				            if(opCode == 8){
				        	socket.getOutputStream().close();
				        	file = null;
							fileOut.flush();
							fileOut.close();
							fileOut = null;
				        	break;
				            }
				            b = in.read();
				            int payloadLength = b & 0x7F;
				            if (payloadLength == 126) {
				                byte[] extended = new byte[2];
				                in.read(extended, 0, 2);
				                int shift = 0;
				                payloadLength = 0;
				            for (int i = extended.length - 1; i >= 0; i--) {
				            	payloadLength = payloadLength + ((extended[i] & 0xFF) << shift);
				                shift += 8;
				            }

				        } else if (payloadLength == 127) {
				            byte[] extended = new byte[8];
				            in.read(extended, 0, 8);
				            int shift = 0;
				            payloadLength = 0;
				            for (int i = extended.length - 1; i >= 0; i--) {
				            	payloadLength = payloadLength + ((extended[i] & 0xFF) << shift);
				                shift += 8;
				            }
				        }
				        
				        //掩码
				        byte[] mask = new byte[4];
				        in.read(mask, 0, 4);
				        int readThisFragment = 1;
				        ByteBuffer byteBuf = ByteBuffer.allocate(payloadLength);
				        while(payloadLength > 0){
				        	 int masked = in.read();
				             masked = masked ^ (mask[(int) ((readThisFragment - 1) % 4)] & 0xFF);
				             byteBuf.put((byte) masked);
				             payloadLength--;
				             readThisFragment++;
				        }
				        byteBuf.flip();
				        if(opCode == 1){
				        	getChar(byteBuf.array());
				        }else
				        	outFile(byteBuf.array());
				        in.read(first, 0, 1);
				    }
				    
				}
				in.close();
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				try {
					if (socket != null)
						socket.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
		private void responseClient(boolean finalFragment) throws IOException {
			ByteBuffer byteBuf = ByteBuffer.allocate(10);
			byteBuf.put("ok".getBytes("UTF-8"));
			OutputStream out = socket.getOutputStream();
			int first = 0x00;
			//是不是输出最后的WebSocket响应片断,默认
	        if (finalFragment) {
	            first = first + 0x80;
	            first = first + 0x1;
	        }
	        out.write(first);
	        

	        if (byteBuf.limit() < 126) {
	            out.write(byteBuf.limit());
	        } else if (byteBuf.limit() < 65536) {
	        	out.write(126);
	        	out.write(byteBuf.limit() >>> 8);
	        	out.write(byteBuf.limit() & 0xFF);
	        } else {
	            // Will never be more than 2^31-1
	        	out.write(127);
	        	out.write(0);
	        	out.write(0);
	        	out.write(0);
	        	out.write(0);
	        	out.write(byteBuf.limit() >>> 24);
	        	out.write(byteBuf.limit() >>> 16);
	        	out.write(byteBuf.limit() >>> 8);
	        	out.write(byteBuf.limit() & 0xFF);

	        }

	        // Write the content
	        out.write(byteBuf.array(), 0, byteBuf.limit());
	        out.flush();
		}
		
		/**
		 * 方法说明:
		 * @开发:linrb
		 * @建立时间:2012-8-21
		 * @param array
		 * @throws IOException 
		 */
		private void getChar(byte[] array) throws IOException {
			ByteArrayInputStream  byteIn = new ByteArrayInputStream(array);
			InputStreamReader reader = new InputStreamReader(byteIn, charset.newDecoder());
			int b = 0;
			String res = "";
			try {
				while((b = reader.read()) > 0){
					res += (char)b;
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			file = new File("C:/" + res);
		}

		/**
		 * 方法说明:
		 * @开发:linrb
		 * @建立时间:2012-8-14
		 * @param array
		 * @throws IOException 
		 */
		private void outFile(byte[] array) throws IOException {
			if(fileOut == null){
				fileOut = new FileOutputStream(file, true);
			}
			fileOut.write(array);
			responseClient(true);
		}
	}

	public static void main(String[] args) throws IOException {
		new UploadServer().service();
	}
}
相关文章
相关标签/搜索