1. 程式人生 > >html5大檔案上傳技術(四)

html5大檔案上傳技術(四)

五、MD5檔案校驗

基於js-spark-md5前端js類庫,可快速獲取檔案Md5值,點選下載:spark-md5.js


一個分片讀取大檔案MD5值得範例(引用)

 <body>  <div>
                <div>                                                             
                    新增檔案
                    <input type="file" name="" id="fileinput">                                                                     
                </div>
                <progress class='progressbar' value="0" max="100" style='width:500px;margin-top:20px'></progress>
                <div style='margin-top:20px'>
                    <span id="handler_info" ></span>
                </div>
            </div>    
      <script src="Scripts/spark-md5.js"></script>
      <script>
        function get_filemd5sum(ofile) {
            var file = ofile;
            var tmp_md5;
            var blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice,
                // file = this.files[0],
                chunkSize = 2 * 1024 * 1024, // Read in chunks of 2MB
                chunks = Math.ceil(file.size / chunkSize),
                currentChunk = 0,
                spark = new SparkMD5.ArrayBuffer(),
                fileReader = new FileReader();
            fileReader.onload = function(e) {
                // console.log('read chunk nr', currentChunk + 1, 'of', chunks);
                spark.append(e.target.result); // Append array buffer
                currentChunk++;
                var md5_progress = Math.floor((currentChunk / chunks) * 100);
                console.log(file.name + "  正在處理,請稍等," + "已完成" + md5_progress + "%");
                var handler_info = document.getElementById("handler_info");
                var progressbar = document.getElementsByClassName("progressbar")[0];
                handler_info.innerHTML=file.name + "  正在處理,請稍等," + "已完成" + md5_progress + "%"
                progressbar.value =md5_progress;
                if (currentChunk < chunks) {
                    loadNext();
                } else {
                    tmp_md5 = spark.end();
                    console.log(tmp_md5)
                    handler_info.innerHTML = file.name + "的MD5值是:" + tmp_md5;
                }
            };
            fileReader.onerror = function() {
                console.warn('oops, something went wrong.');
            };
            function loadNext() {
                var start = currentChunk * chunkSize,
                    end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
                fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
            }
            loadNext();
        }
        var uploadfile  = document.getElementById('fileinput')
        uploadfile.onchange = function(e){
            var file = this.files[0];
             if(!file) {
                alert('請選擇檔案!');
                return false;
            }
            get_filemd5sum(file)
        }
    </script>
           
   </body> 

通過計算可以獲得檔案唯一的的md5值,因此在做檔案上傳的時候,就只要在前端先獲取要上傳的檔案md5,並把檔案md5傳到伺服器,對比之前檔案的md5,如果存在相同的md5,我們只要把檔案的名字傳到伺服器關聯之前的檔案即可,並不需要再次去上傳相同的檔案,再去耗費儲存資源、上傳的時間、網路頻寬。

範例:客戶端與伺服器端檔案MD5的簡單匹配。

客戶端程式碼:

<body>
     <div>
         <div>  新增檔案 <input type="file" name="" id="fileinput"/>
             <input id="Button1" type="button" onclick ="get_filemd5sum()" value="提交" /></div> 
 <progress class='progressbar' value="0" max="100" style='width:500px;margin-top:20px'></progress>
         <div style='margin-top:20px'>
         <span id="handler_info" ></span>
         </div>
         </div> 
    <script src="Scripts/jquery-3.2.1.js"></script>
    <script src="Scripts/spark-md5.js"></script>
<script>
    function has_file_by_md5(file, fileMD5) {
        name = file.name;					//檔名
        size = file.size;					//總大小
        //構造一個表單,FormData是HTML5新增的
            var form = new FormData();
            form.append("name", name);
            form.append("file_md5", fileMD5);
            form.append("size", size);	//檔案大小
           //Ajax提交
            $.ajax({
                url: "File/temp_md5.aspx",
                type: "POST",
                data: form,
                processData: false,			//很重要,告訴jquery不要對form進行處理
                contentType: false			//很重要,指定為false才能形成正確的Content-Type
            }).done(function (msg, status) {
                if (msg == "ok") {
                     handler_info.innerHTML+="<br>伺服器端存在此檔案!"
                } else {
                    handler_info.innerHTML += "<br>伺服器端不存在此檔案!"
                }               
            });
      };
        function get_filemd5sum() { 
            var file = document.getElementById('fileinput').files[0];
            if (!file) {
                alert('請選擇檔案!');
                return false;
            }
        var tmp_md5="";
        var shardSize = 2 * 1024 * 1024;		//以2MB為一個分片
        //獲取檔案MD5的值/*** 大檔案很慢,只讀取第一片****/
        var blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice,
            spark = new SparkMD5.ArrayBuffer(),
            fileReader = new FileReader();
        var start = 0, end = ((start + shardSize) >= file.size) ? file.size : start + shardSize;
        fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
        fileReader.onload = function (e) {
            spark.append(e.target.result); // Append array buffer
            tmp_md5 = spark.end();  
            var progressbar = document.getElementsByClassName("progressbar")[0];
            progressbar.value = 100;                        
            //傳送MD5到伺服器
                console.log(tmp_md5)
                has_file_by_md5(file, tmp_md5);
                handler_info.innerHTML = file.name + "的MD5值是:" + tmp_md5;
            }       
        fileReader.onerror = function () {
            console.warn('oops, something went wrong.');
        }
    };
</script>
</body>

服務端temp_md5.aspx程式碼:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class temp_md5 : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        string msg = "";
        try
        {
         //從Request中取引數,注意上傳的檔案在Requst.Files中
            string name = Request["name"];
            string file_md5 = Request["file_md5"];
            long size_total = Convert.ToInt64(Request["size"]);                                   
            string dir = Server.MapPath("~/Upload");
            string big_file = Path.Combine(dir, name); 
            string file_name = Path.Combine(dir, name); //檔案
            int shardSize = 2 * 1024 * 1024;		//以2MB為一個分片
            if (System.IO.File.Exists(big_file) == true)//檔案已經上傳
            {
                FileInfo tempfileinfo = new FileInfo(big_file);//md5相同,檔案大小相同,同一個檔案,秒傳
                if (tempfileinfo.Length == size_total)
                {
                    if (file_md5 == get_file_md5(name, dir, shardSize))
                    {
                        msg="ok";
                    }
                }
            }            
        }
        catch (Exception)
        {
            msg = "error";
        }
        Response.Write(msg);
    }
    public string get_file_md5(string filename, string dir, int shardSize)
    {
        string msg = "";
        try
        {
            string file_N = Path.Combine(dir, filename);
            FileInfo temp_file_info = new FileInfo(file_N);
            long start = 0;
            long end = Math.Min((long)(temp_file_info.Length), start + shardSize); //大檔案取第一片生成臨時檔案
            string temp_file_name = "";
            if (temp_file_info.Length > shardSize)
            {
            temp_file_name = Path.Combine(dir, filename + "_temp");
            FileStream file = new FileStream(file_N, System.IO.FileMode.Open);
            BinaryReader br = new BinaryReader(file);
              byte[] bs = br.ReadBytes(Convert.ToInt32(end));;
            br.Close();
            file.Close();
            FileStream temp_file = new FileStream(temp_file_name, FileMode.Create, FileAccess.Write);
            temp_file.Write(bs, 0, bs.Length);
            temp_file.Close();
            }else
            {
                temp_file_name = Path.Combine(dir, filename);
            }
            FileStream file1 = new FileStream(temp_file_name, System.IO.FileMode.Open);
            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] retVal = md5.ComputeHash(file1);
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < retVal.Length; i++)
            {
                sb.Append(retVal[i].ToString("x2"));
            }
            msg = sb.ToString();
            file1.Close();
            if (temp_file_info.Length > shardSize)
            {
                System.IO.File.Delete(temp_file_name);//刪除臨時生成的檔案
            }

        }
        catch (Exception)
        {
            msg = "error";
        }
        return (msg);
    }
}