標籤:
http://www.iteye.com/topic/1127319
前天第一次發表部落格到論壇,關於Java檔案監控一文,文章地址在:http://www.iteye.com/topic/1127281
評論的朋友很多,下載代碼的朋友很不少,感謝在論壇上看我文章的朋友,還有回複評論的朋友,給我提供建議的朋友。
從這些建議中,雖然語言簡短,但是卻有的是一語中的,這裡說一下一下關於文章的代碼中HashFile中的MD5檔案校正演算法,
該演算法是使用Java內建的MessageDigest類,測試結果,擷取一個2G檔案的MD5碼,耗時 971秒,這效率太給力了,可以用坑爹來形容,所以用MD5檔案校正碼來判斷檔案是否被修改,對於小檔案來說可能還合適,要是對大檔案來說,好吧,撞牆死了算了!
HashFile中的代碼是這樣子的:
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.MessageDigest;
public class HashFile {
/**
* @param args
*/
public static char[] hexChar = { ‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘,
‘8‘, ‘9‘, ‘a‘, ‘b‘, ‘c‘, ‘d‘, ‘e‘, ‘f‘ };
public static String getHash(String fileName, String hashType)
throws Exception {
InputStream fis;
fis = new FileInputStream(fileName);
byte[] buffer = new byte[1024];
MessageDigest md5 = MessageDigest.getInstance(hashType);
int numRead = 0;
while ((numRead = fis.read(buffer)) > 0) {
md5.update(buffer, 0, numRead);
}
fis.close();
return toHexString(md5.digest());
}
public static String toHexString(byte[] b) {
StringBuilder sb = new StringBuilder(b.length * 2);
for (int i = 0; i < b.length; i++) {
sb.append(hexChar[(b[i] & 0xf0) >>> 4]);
sb.append(hexChar[b[i] & 0x0f]);
}
return sb.toString();
}
}
測試結果:
真給力啊,超過2G,效率變成這樣 !
好吧,內建的MD5演算法,上當了,對於檢查檔案是否更新這個問題來說,現在我使用的解決辦法是File 類的lastModified方法,代碼這樣
private String getHash(String fp){
File file = new File(fp);
return String.valueOf(file.lastModified());
}
通過比較檔案的最後修改時間來判斷檔案是否更新,對大檔案也輕鬆拿下,
測試結果是這樣:
當然針對不同問題肯定是有不同的解決辦法
分析原來HashFile代碼,擷取MD5校正碼的瓶頸是出現在
Java代碼
- public static String getHash(String fileName, String hashType)
- throws Exception {
- InputStream fis;
- fis = new FileInputStream(fileName);
- byte[] buffer = new byte[1024];
- MessageDigest md5 = MessageDigest.getInstance(hashType);
- int numRead = 0;
- while ((numRead = fis.read(buffer)) > 0) { //瓶頸
- md5.update(buffer, 0, numRead);
- }
- fis.close();
- return toHexString(md5.digest());
- }
public static String getHash(String fileName, String hashType) throws Exception { InputStream fis; fis = new FileInputStream(fileName); byte[] buffer = new byte[1024]; MessageDigest md5 = MessageDigest.getInstance(hashType); int numRead = 0; while ((numRead = fis.read(buffer)) > 0) { //瓶頸 md5.update(buffer, 0, numRead); } fis.close(); return toHexString(md5.digest()); }
在上面代碼中,while迴圈N次,2G的檔案,迴圈1024 * 1024 * 2 次,不給力!
chimer回複
來個nio的簡單版,看你們老是懷疑java慢
C++ MD5工具驗證結果:
File: K:\Games\World of Warcraft\Data\common.MPQ
Size: 2226587191 bytes
Modified: 2008年11月19日 星期三, 12:57:24
MD5: CD9F9C5523F3BA3866B81CCC74ED6476
java運行結果,毫秒
耗時:12672,cd9f9c5523f3ba3866b81ccc74ed6476
核心代碼
String hashType = "MD5";
FileInputStream fStream = null;
try {
MessageDigest md5 = MessageDigest.getInstance(hashType);
fStream = new FileInputStream(
//"K:\\Games\\World of Warcraft\\Scan.dll");
//"K:\\Games\\World of Warcraft\\Data\\patch-3.MPQ");
"K:\\Games\\World of Warcraft\\Data\\common.MPQ");
FileChannel fChannel = fStream.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(8*1024);
long s = System.currentTimeMillis();
for ( int count = fChannel.read( buffer ); count !=-1 ; count = fChannel.read( buffer )
) {
buffer.flip();
md5.update( buffer );
if( !buffer.hasRemaining() ){
//System.out.println("count:"+count);
buffer.clear();
}
}
s = System.currentTimeMillis() - s;
System.out.println( "耗時:"+s+","+getString( md5.digest() ) );
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
if( fStream!=null )
fStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Java 內建MD5 校正檔案