这次要认认真真的写一篇文章了,咳咳。 关于如何前台生成文件hash的文章。
之前在网上找了很多文章都没有特别详细的内容,最后根据一些信息还有自己的摸索,做了出来,所以借以分享给大家。
首先我先来简单说说hash,它的意思是通过一个算法,将一串数据通过运算变换成一个固定长度的摘要(或者说指纹),然后我们可以在数据交换的时候用它来对数据的内容进行校验等等。
举个栗子:最近我就这么用了用它,当客户端向服务器传输数据的时候,需要先向服务器提供文件的hash,然后如果服务器包含了同样hash的文件,那么返回信息不需要客户端上传,只用给用户建立一个链接就好,如果没有,那么就要求客户端上传文件。
于是就牵扯到了这个问题,就是在html前台生成文件的hash,然后发给服务器,等待服务器回复。
研究了很久终于实现了。是借用了一个名叫crypto-js的加密库实现的。这是它在googlecode上的项目地址:https://code.google.com/p/crypto-js/
闲话少说,具体实现是这么做的:
首先要先在网页上有一个文件选取的框:
<input type=”file” />
它的效果是这样的:
当然它具体长什么样要看用户使用的浏览器了。不过没关系后边我就要说怎么样美化这个框框。
可以看到已经可以通过这个框框来选取文件了。然后我们就要在js上边下功夫了。
首先我们给这个输入的框一个可以被js调用的id。
<input id=”UploadFile” type=”file” />
然后我们开始写js:
function FileHashCreat(){
var fileReader = new FileReader(); //建立一个FileReader对象
var BlobSlice = File.prototype.mozSlice || File.prototype.webkitSlice || File.prototype.slice; //用于支持多种浏览器的文件读取
file = document.getElementById(“UploadFile”).files[0]; //通过id获取html中input标签的文件
var BlockSize = 10485760; //要把文件分成一块一块的,这样可以应对巨大的文件而不至于出错,这里将文件以10M为单位进行分割。
var Blocks = Math.ceil(file.size / BlockSize); //首先计算需要分割的块数
var CurrentBlock = 0; //记录当前已经运行的块数
var FileSHA256 = CryptoJS.algo.SHA256.create(); //新建一个对象
var start = 0;
var end = start + BlockSize >= file.size ? file.size : start + BlockSize;
//这一句可以等价为:
/****************
var end = 0;
if (start + BlockSize >= file.size){
end = file.size;
}else{
end = start + BlockSize;
}
****************/
//防止读取文件的长度发生错误
fileReader.readAsArrayBuffer(BlobSlice.call(file, start, end));
fileReader.onload = function(filestring) { //文件读取过程
FileSHA256.update(arrayBufferToWordArray(filestring.target.result)); //根据其项目中的描述,可以通过这种方法将数据分段后加载,但是因为crypto-js这个库不能直接接受arraybuffer,所以要进行转换。
CurrentBlock++; //文件区块后移
if (CurrentBlock < Blocks) { //判断是否到达文件末尾
start = CurrentBlock * Blocksize; //更新文件区块开始结束的位置
end = start + BlockSize >= file.size ? file.size : start + BlockSize;
fileReader.readAsArrayBuffer(BlobSlice.call(file, start, end)); //加载下一个区段
} else {
var FileHash = FileSHA256.finalize(); //获取最终的文件hash,注意这个finalize只能调用一次,多次调用会出错。
}
}
}
//arraybuffer to wordarray 的转换函数
function swapendian32(val) {
return (((val & 0xFF) << 24)
| ((val & 0xFF00) << 8)
| ((val >> 8) & 0xFF00)
| ((val >> 24) & 0xFF)) >>> 0;
}
function arrayBufferToWordArray(arrayBuffer) {
var fullWords = Math.floor(arrayBuffer.byteLength / 4);
var bytesLeft = arrayBuffer.byteLength % 4;
var u32 = new Uint32Array(arrayBuffer, 0, fullWords);
var u8 = new Uint8Array(arrayBuffer);
var cp = [];
for (var i = 0; i < fullWords; ++i) {
cp.push(swapendian32(u32[i]));
}
if (bytesLeft) {
var pad = 0;
for (var i = bytesLeft; i > 0; –i) {
pad = pad << 8;
pad += u8[u8.byteLength – i];
}
for (var i = 0; i < 4 – bytesLeft; ++i) {
pad = pad << 8;
}
cp.push(pad);
}
return CryptoJS.lib.WordArray.create(cp, arrayBuffer.byteLength);
};
至此就实现了所述功能。
这是一个demo,可以试试:
前台生成文件hash
===============我是分界线=================
如果想要美化那个丑丑的文件选择框的话,可以直接给他加个style=”display:none;”,然后再在自己画的按键或者标签的那里加上:
document.getElementById(“UploadFile”).click();
就可以了!