byte[]轉(zhuǎn)16進(jìn)制bug總結(jié)

          (一)問(wèn)題

                   項(xiàng)目中需要對(duì)文件做md5sum,分兩步走:1、對(duì)文件流的每個(gè)字節(jié)用md5實(shí)例進(jìn)行update,然后進(jìn)行digest2digest返回長(zhǎng)度為16byte數(shù)組,一般我們需要把byte數(shù)組轉(zhuǎn)成16進(jìn)制字符串(很多開(kāi)源的md5加密算法如此實(shí)現(xiàn),真正的原因還不是很理解,可能是便于查看和傳輸)。具體的實(shí)現(xiàn)代碼如下:

                   /**

              * 對(duì)文件進(jìn)行md5 sum操作

              * @param checkFile 要進(jìn)行做md5 sum的文件

              * @return

              */

              public static String md5sum(File checkFile){

                 String md5sumResult = "";

                 if(checkFile == null || (!checkFile.exists())){

                     return md5sumResult;

                 }

                 MessageDigest digest = MessageDigest.getInstance("MD5");

                 InputStream is = new FileInputStream(checkFile);

                 byte[] buffer = new byte[8192];

                 int read = 0;

                 try {

                     while( (read = is.read(buffer)) > 0) {

                        digest.update(buffer, 0, read);

                     }

                     byte[] md5sum = digest.digest();

                     BigInteger bigInt = new BigInteger(1, md5sum);

                     md5sumResult = bigInt.toString(16);

                 }

                 catch(IOException e) {

                     throw new RuntimeException("Unable to process file for MD5", e);

                 }

                 finally {

                     try {

                        is.close();

                     }

                     catch(IOException e) {

                        throw new RuntimeException("Unable to close input stream for MD5 calculation", e);

                     }

                 }

                

                 return md5sumResult;

              }

           

              其中黃色背景色的轉(zhuǎn)換方式是有問(wèn)題的。為什么用bigint轉(zhuǎn)16進(jìn)制會(huì)有問(wèn)題呢,原因是bigint進(jìn)行16進(jìn)制轉(zhuǎn)換的時(shí)候第一個(gè)0被自動(dòng)去掉了.

             

           

          (二)正確解決方式

          那正確的方式是怎么樣的呢?下面有兩種不同的轉(zhuǎn)換方式,但是原理其實(shí)是一致的。

              第一種正確的方式(由王建提供):

              /**

              * 將字節(jié)數(shù)組轉(zhuǎn)換為16進(jìn)制字符串

              *

              * @param buffer

              * @return

              */

             public static String toHex(byte[] buffer) {

                StringBuffer sb = new StringBuffer(buffer.length * 2);

                for (int i = 0; i < buffer.length; i++) {

                 sb.append(Character.forDigit((buffer[i] & 240) >> 4, 16));

                 sb.append(Character.forDigit(buffer[i] & 15, 16));

                }

           

                return sb.toString();

             }

           

              第二種正確的方式:

              public static String bytes2HexString(byte[] b) {

                 String ret = "";

                 for (int i = 0; i < b.length; i++) {

                     String hex = Integer.toHexString(b[i] & 0xFF);

                     if (hex.length() == 1) {

                        hex = '0' + hex;

                     }

                     ret += hex;

                 }

                 return ret;

              }

           

          (三)問(wèn)題分析

              Md5算法對(duì)任何長(zhǎng)度的字符串進(jìn)行編碼最后輸出是128位長(zhǎng)整數(shù),也就是長(zhǎng)度為16byte數(shù)組。我們項(xiàng)目調(diào)用的是jdk實(shí)現(xiàn)的md5算法,所以一般是沒(méi)問(wèn)題的。

              接下來(lái)我們要處理的事情,分別循環(huán)數(shù)組,把每個(gè)字節(jié)轉(zhuǎn)換成2個(gè)16進(jìn)制字符,也就是說(shuō)每4位轉(zhuǎn)成一個(gè)16進(jìn)制字符。

             

              上面正確的兩種方式也就是做了這樣的事情。

              第一種方式:

                 Character.forDigit((buffer[i] & 240) >> 4, 16)把字節(jié)的高4位取出右移4位換算成int,然后通過(guò)forDigit轉(zhuǎn)換成16進(jìn)制字符

                 Character.forDigit(buffer[i] & 15, 16)把字節(jié)的低4位取出換算成int,然后通過(guò)forDigit轉(zhuǎn)換成16進(jìn)制字符

             

              第二種方式:

                 Integer.toHexString(b[i] & 0xFF)把整個(gè)字節(jié)轉(zhuǎn)成int,然后toHexString也就是做高4位和低4位的運(yùn)算。但是這個(gè)方法如果高四位是0的話就不輸出任何東西,

          所以在輸出的字符前加0即可。

                 b[i] & 0xFF就是把byte轉(zhuǎn)成int,為什么用與oxff做與運(yùn)算,是因?yàn)槿绻?/span>b[i]是負(fù)數(shù)的話,從8位變成32位會(huì)補(bǔ)1,所以需要與0xff做與運(yùn)算,可以把前面的24位全部清零,又可以表示成原來(lái)的字節(jié)了。

             

           

          附:

          盡量使用開(kāi)源提供的工具包,比如:

          org.apache.commons.codec.digest.DigestUtils.md5Hex(InputStream data)來(lái)對(duì)文件流進(jìn)行md5即可,更加方便,可靠。

          posted on 2012-01-10 14:39 yangpingyu 閱讀(8071) 評(píng)論(2)  編輯  收藏 所屬分類: java基礎(chǔ)

          評(píng)論

          # re: byte[]轉(zhuǎn)16進(jìn)制bug總結(jié) 2013-06-04 11:20 緣分情空

          解釋的很有道理  回復(fù)  更多評(píng)論   

          # re: byte[]轉(zhuǎn)16進(jìn)制bug總結(jié)[未登錄](méi) 2013-07-10 16:51 Rain

          謝謝,正好解決問(wèn)題  回復(fù)  更多評(píng)論   

          <2012年1月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          2930311234

          導(dǎo)航

          統(tǒng)計(jì)

          常用鏈接

          留言簿

          隨筆分類

          隨筆檔案

          收藏夾

          linux

          產(chǎn)品交互

          分析,設(shè)計(jì),架構(gòu)

          安全

          技術(shù)牛人

          數(shù)據(jù)庫(kù)

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 偏关县| 乐亭县| 西乌珠穆沁旗| 雅江县| 洞口县| 湄潭县| 云浮市| 太保市| 商水县| 淳化县| 姚安县| 临安市| 当涂县| 南漳县| 龙门县| 三台县| 北流市| 长沙市| 西华县| 运城市| 容城县| 楚雄市| 沅陵县| 来凤县| 杭锦旗| 基隆市| 桃源县| 肇源县| 北碚区| 常州市| 龙里县| 瑞昌市| 吉隆县| 通榆县| 新蔡县| 潮州市| 扶绥县| 筠连县| 舟曲县| 灵璧县| 大连市|