/**
* 读取指定文件块数据Sha1
*
* @param fis
* @return
*/
private static MessageDigest calSha1(BufferedInputStream fis) {
MessageDigest sha1 = null;
try {
byte[] buffer = new byte[1024];
int numRead = 0;
int total = 0;
sha1 = MessageDigest.getInstance("SHA-1");
while ((numRead = fis.read(buffer)) > 0) {
sha1.update(buffer, 0, numRead);
total += numRead;
if (total >= BLOCK_SIZE) {//每次最多读入4M
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return sha1;
}
/**
* 获取hash/etag,根据File文件计算hash值
*
* @param file 文件
* @return
*/
public static String getEtagHash(File file) {
String etagHash = null;
BufferedInputStream fis = null;
try {
if (file.exists()) {
byte[] ret = new byte[21];
long blockCount = blockCount(file.length());
fis = new BufferedInputStream(new FileInputStream(file));
if (blockCount <= 1) { // 文件块数小于等于1块
MessageDigest sha1 = calSha1(fis);
if (null != sha1) {
byte[] input = sha1.digest();
ret[0] = BYTE_LOW_4;
for (int i = 0; i < 20; ++i) {//SHA1算法位20字节
ret[i + 1] = input[i];
}
}
} else {//将所有sha1值按切块顺序拼接
byte[] rec = new byte[(int) blockCount * 20];
ret[0] = BYTE_OVER_4;
int i, cnt = 0;
for (i = 0; i < blockCount; i++) {//每块文件分别计算sha1
MessageDigest sha1 = calSha1(fis);
if (null != sha1) {
byte[] tmp = sha1.digest();
for (int j = 0; j < 20; j++) {
rec[cnt++] = tmp[j];
}
}
}
MessageDigest sha1 = MessageDigest.getInstance("SHA-1");//对拼接好的数据再做sha1计算
sha1.update(rec, 0, (int) blockCount * 20);
byte[] tmp = sha1.digest();
for (i = 0; i < 20; ++i) {//在最前面拼上单个字节,值为0x96
ret[i + 1] = tmp[i];
}
}
etagHash = EncodeUtils.urlsafeEncodeString(ret);
} else {
System.out.println("File[" + file.getAbsolutePath() + "] Not Exist,Cannot Calculate Hash!");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fis != null) {
fis.close();
fis = null;
}
} catch (IOException e) {
e.printStackTrace();
}
}
return etagHash;
}
使用 System.Security.Cryptography.HashAlgorithm
抽象类创建 SHA1 实例,再调用其 ComputeHash
等方法计算 Hash
HashAlgorithm hash = HashAlgorithm.Create("SHA1");
byte[] code = hash.ComputeHash(Encoding.UTF8.GetBytes("abcdefg"));
Console.WriteLine(BitConverter.ToString(code));
// 2F-B5-E1-34-19-FC-89-24-68-65-E7-A3-24-F4-76-EC-62-4E-87-40
如果要算一个文件的 Hash,用 HashAlgorithm.ComputeHash(Stream)
,需要先用 System.IO.FileStream
把文件打开为 Stream
HashAlgorithm sha1 = HashAlgorithm.Create("sha1");
byte[] result;
using (FileStream fs = new FileStream(filename, FileMode.Open)) {
result = sha1.ComputeHash(fs);
}
Console.WriteLine(BitConverter.ToString(result).Replace("-", string.Empty));
补充一下
数值和类型转换可以使用 Viyi.Util 中的扩展方法。
十六进制字符串和 byte] 之间可以参考 [ASCII编码解码:Base64和Hex