1. 程式人生 > >使用webuploader上傳大檔案

使用webuploader上傳大檔案

遇到一個需求,使用者想上傳超過1、2G的視訊檔案。

根據這個需求做了一些上傳速度對比,ftp上傳1G多點的檔案用時三分鐘左右

1.使用ftp上傳

(1) 建立ftp服務站點
在伺服器上依次選擇控制面板——管理工具——計算機管理——Internet 資訊服務(IIS)——FTP站點——建立站點 (埠設定要避開預設埠設定其他的)
(2) 在使用者組建立一個專案相關使用者,設定使用者名稱和密碼
(設定密碼永不過期) (3 ) 在ftp站點許可權設定
右鍵選中站點——  許可權——新增上一步設定的使用者。
(4) 實現ftp上傳 <1> 將如上配置儲存在ftp.properties中方便程式碼呼叫. <2> 上傳
	/**
	 * 上傳檔案
	 * 
	 * @param hostname
	 *            FTP伺服器地址
	 * @param port
	 *            FTP伺服器埠號
	 * @param username
	 *            FTP登入帳號
	 * @param password
	 *            FTP登入密碼
	 * @param pathname
	 *            FTP伺服器儲存目錄
	 * @param fileName
	 *            上傳到FTP伺服器後的檔名稱
	 * @param inputStream
	 *            輸入檔案流
	 * @return
	 */
	public static boolean uploadFile(String hostname, int port,
			String username, String password, String pathname, String fileName,
			InputStream inputStream) {
		boolean flag = false;
		long startTime=System.currentTimeMillis();
		FTPClient ftpClient = new FTPClient();
		ftpClient.setControlEncoding("UTF-8");
		try {
			// 連線FTP伺服器
			ftpClient.connect(hostname, port);
			// 登入FTP伺服器
			ftpClient.login(username, password);
			// 是否成功登入FTP伺服器
			int replyCode = ftpClient.getReplyCode();
			if (!FTPReply.isPositiveCompletion(replyCode)) {
				return flag;
			}
			//ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
			ftpClient.makeDirectory(pathname);
			ftpClient.changeWorkingDirectory(pathname);
			ftpClient.storeFile(fileName, inputStream);
			inputStream.close();
			ftpClient.logout();
			flag = true;
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (ftpClient.isConnected()) {
				try {
					ftpClient.disconnect();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		long endTime=System.currentTimeMillis();
		float excTime=(float)(endTime-startTime)/1000;
	    System.out.println("執行時間:"+excTime+"s");
		return flag;
	}

2.使用webuploader上傳,集成了進度條.


 (1)前端頁面

	<link rel="stylesheet" type="text/css" href="js/webuploader/webuploader.css" />
	<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
	<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
	<link rel="stylesheet" type="text/css" href="js/webuploader/style.css" />

						<input type="hidden" id="fileUrl" name="news.fileUrl">
						<div id="uploader" class="wu-example">
							<div class="btns">
								<div id="attach"></div>
								<div id="thelist" class="uploader-list"></div>
								<a id="upload" href="javascript:void(0)" class="easyui-linkbutton">上傳檔案</a>
							</div>
						</div>
					    <script type="text/javascript" src="js/webuploader/webuploader.js"></script>
					    <script type="text/javascript" src="js/webuploader/upload.js"></script>
						
						<div style="text-align:center;clear:both;">
							<script src="js/other/gg_bd_ad_720x90.js" type="text/javascript"></script>
							<script src="js/other/follow.js" type="text/javascript"></script>
						</div>

(2)進度條樣式檔案

body{
	background: #a8b1b6;
	color: #2fa0ec;
	font-weight: 500;
	font-size: 1.05em;
	font-family: "Microsoft YaHei","宋體","Segoe UI", "Lucida Grande", Helvetica, Arial,sans-serif, FreeSans, Arimo;
}
a{color: #d8dedc;outline: none;}
a:hover,a:focus{color:#74777b;text-decoration: none;}
.progress{
    height: 30px;
    line-height: 35px;
    background: #809495;
    box-shadow: none;
    padding: 6px;
    margin-top:20px;
    overflow: visible;
    border-radius:10px;
}
.progress:after{
    content: "";
    display: block;
    border-top: 4px dashed #fff;
    margin-top:8px;
}
.progressbar-title{
    color:#d8dedc;
    font-size:15px;
    margin:5px 0;
    font-weight: bold;
}
.progress .progress-bar{
    position: relative;
    border-radius: 10px 0 0 10px;
    animation: animate-positive 2s;
}
.progress .progress-bar span{
    position: absolute;
    top: -50px;
    right: -40px;
    color: #fff;
    display: block;
    font-size: 17px;
    font-weight: bold;
    padding: 5px 7px;
    background: #333;
    border-radius: 0 0 5px 5px;
}
.progress .progress-bar span:before{
    content: "";
    position: absolute;
    bottom: -14px;
    left: 18px;
    border: 7px solid transparent;
    border-top: 7px solid #333;
}
.progress .progress-bar span:after{
    content: "\f072";
    font-family: fontawesome;
    font-size: 48px;
    color: #333;
    position: absolute;
    top: 51px;
    right: 6px;
    transform: rotateZ(48deg);
}
@-webkit-keyframes animate-positive {
    0% { width: 0%;}
}
@keyframes animate-positive {
    0% { width:0%; }
}


 (3) 上傳檔案 upload.js

/**
 * *******************************WebUpload 單檔案上傳begin****************************************
 */
_extensions ='3gp,mp4,rmvb,mov,avi,m4v,mkv';
_mimeTypes ='video/*,audio/*,application/*';

$(function() {
	var $list = $("#thelist");
	var uploader;// 例項化
	uploader = WebUploader.create( {
		auto : false, // 是否自動上傳
		pick : {
			id : '#attach',
			name : "file", // 這個地方 name
							// 沒什麼用,雖然開啟偵錯程式,input的名字確實改過來了。但是提交到後臺取不到檔案。如果想自定義file的name屬性,還是要和fileVal
							// 配合使用。
			label : '點選選擇檔案',
			multiple : false
		// 預設為true,就是可以多選
		},
		swf : 'js/webuploader/Uploader.swf',
		// fileVal:'multiFile', //自定義file的name屬性,我用的版本是0.1.5 ,開啟客戶端偵錯程式發現生成的input
		// 的name 沒改過來。
		// 名字還是預設的file,但不是沒用哦。雖然客戶端名字沒改變,但是提交到到後臺,是要用multiFile 這個物件來取檔案的,用file
		// 是取不到檔案的
		server : "videoAction!ajaxAttachUpload.action",
		duplicate : true,// 是否可重複選擇同一檔案
		resize : false,
		formData : {
			"status" : "file",
			"contentsDto.contentsId" : "0000004730",
			"uploadNum" : "0000004730",
			"existFlg" : 'false'
		},
		compress : null,
		chunked : true, // 分片處理
		chunkSize : 50 * 1024 * 1024, // 每片50M,經過測試,發現上傳1G左右的視訊大概每片50M速度比較快的,太大或者太小都對上傳效率有影響
		chunkRetry : false,// 如果失敗,則不重試
		threads : 1,// 上傳併發數。允許同時最大上傳程序數。
		// runtimeOrder: 'flash',
		disableGlobalDnd : true,
		accept: {      
            title: '視訊檔案上傳',  //文字描述
            extensions: _extensions,     //允許的檔案字尾,不帶點,多個用逗號分割。,jpg,png,
            mimeTypes: _mimeTypes,      //多個用逗號分割。,
        }
	});
	// 當有檔案新增進來的時候
	uploader.on("fileQueued", function(file) {
		console.log("fileQueued:");
		$list.html("
" + "

" + file.name + "

" + "

等待上傳...

" + " "); }); // 當所有檔案上傳結束時觸發 uploader.on("uploadFinished", function() { console.log("uploadFinished:"); }); // 當某個檔案上傳到服務端響應後,會派送此事件來詢問服務端響應是否有效。 uploader.on("uploadAccept", function(object, ret) { // 伺服器響應了 var data = JSON.parse(ret._raw); if (data.isSuccess == "1" || data.isSuccess == "3") { $("#fileUrl").val(data.fileUrl); } else { uploader.reset(); alert("上傳檔案出現異常,請重新整理後重新嘗試。"); return false; } }); uploader.on('uploadProgress', function (file, percentage) {//進度條事件 var $li = $list.find('#' + file.id), $percent = $li.find('#ProcessWD'); // 避免重複建立 if (!$percent.length) { $percent = $('

上傳進度

' + ' ' + ' ' + ' ').appendTo($li).find('.progress-bar'); } $("#" + file.id).find("p.state").text('正在上傳'); $("#fileProcess").text(Math.round(percentage * 100) + '%'); $("#ProcessWD").css('width', percentage * 100 + '%'); }); // 當檔案上傳成功時觸發。 uploader.on("uploadSuccess", function(file) { $("#" + file.id).find("p.state").text("已上傳成功"); }); uploader.on("uploadError", function(file) { $("#" + file.id).find("p.state").attr("color","red"); $("#" + file.id).find("p.state").text("上傳出錯"); uploader.cancelFile(file); uploader.removeFile(file, true); uploader.reset(); }); /** * 驗證檔案格式以及檔案大小 */ uploader.on("error",function (type,handler){ if (type=="Q_TYPE_DENIED"){ $.messager.alert('提示視窗','請上傳MP4格式的視訊!'); } }); $("#upload").on("click", function() { $("#showJD").attr("display","block"); $('#upload').linkbutton('disable'); uploader.upload(); }) });
(4) 後臺上傳處理
	//視訊檔案上傳
	private File file;
	private String fileFileName;

	//屬性值,接收webupload自帶的引數
	private String chunk; // 當前第幾個分片
	private String chunks;// 總分片個數
	private String size;// 單個檔案的總大小	

	......

	/**
	 * 檔案上傳儲存
	 * @return
	 */
	public String ajaxAttachUpload() {
	Map<String, Object> map = new HashMap<String, Object>();
        try {
            String fileUrl = CommonConstants.UPLOAD_VIDEO +fileFileName;
            fileUrl = fileUrl.replace("\\", "/");
            FileUtil.randomAccessFile(fileUrl,file);
            if(EmptyUtils.isEmptyString(chunk)){
            	map.put("isSuccess", 1);//不分片的情況
            }else{
	            if (Integer.valueOf(chunk) == (Integer.valueOf(chunks) - 1)) {//分片的情況
	            	map.put("isSuccess", 1);
	            } else {
	            	map.put("isSuccess", 3);
	            }
	        }
            map.put("fileUrl", saveDir);
        } catch (Exception e) {
        	map.put("isSuccess", 2);
        }
        request.setAttribute("records", JSONObject.fromObject(map));
        return "back";
    }
    .......

    /**
     * 指定位置開始寫入檔案
     * @param tempFile  輸入檔案
     * @param outPath  輸出檔案的路徑(路徑+檔名)
     * @throws IOException
     */
    public static void randomAccessFile(String outPath,File tempFile) throws IOException{
        RandomAccessFile  raFile = null;
        BufferedInputStream inputStream=null;
        try{
            File dirFile = new File(outPath);
            File parentDir = dirFile.getParentFile();
			if (!parentDir.exists()) {
				FileUtils.forceMkdir(parentDir);
			}
            //以讀寫的方式開啟目標檔案
            raFile = new RandomAccessFile(dirFile, "rw"); 
            raFile.seek(raFile.length());
            inputStream = new BufferedInputStream(new FileInputStream(tempFile));
            byte[] buf = new byte[1024];
            int length = 0;
            while ((length = inputStream.read(buf)) != -1) {
                raFile.write(buf, 0, length);
            }
        }catch(Exception e){
        	e.printStackTrace();
            throw new IOException(e.getMessage());
        }finally{
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (raFile != null) {
                    raFile.close();
                }
            }catch(Exception e){
                throw new IOException(e.getMessage());
            }
        }
    }

(5)視訊檢視
					<video width="75%" controls="controls" autoplay="autoplay">
						<source src="${pageContext.request.contextPath}/${n.fileUrl}" type="video/ogg" />
						<source src="${pageContext.request.contextPath}/${n.fileUrl}" type="video/mp4" />
						您的瀏覽器不支援此種視訊格式。
					</video>

使用ftp上傳大檔案太慢了,最後選擇了百度的webuploader,測試下來效果還不錯。


以上