2014-02-10 93 views
0

我想從內存中讀取文件並將其分割爲1KB塊。使用java讀取文件爲1KB塊

該程序的功能是從內存中讀取文件(視頻文件),然後將其分割爲1KB的塊。然後使用SHA-256對最後一個塊進行散列並將散列追加到最後一個塊。然後它將第二個最後一個塊和附加散列的散列計算在一起,然後將該散列附加到其前一個塊。這繼續下去,直到第一個塊,它將有第二個塊的散列附加到它。

我只需要第一個塊和它的附加散列的散列。我試圖用兩種方式來實現這一點,但我認爲我做錯了。有人能告訴我我做錯了什麼嗎?我一直堅持6天沒有解決方案。我在下面粘貼了兩個我的實現。任何幫助,將不勝感激。

我已經讀取了整個文件,並嘗試在下面的嘗試中手動將字節數組拆分爲1KB塊。

package com.test; 

import java.io.BufferedInputStream; 
import java.io.FileInputStream; 
import java.io.InputStream; 
import java.security.MessageDigest; 
import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.List; 

public class ReadFileByteByByte { 

    public static void main(String[] args) throws Exception { 

     InputStream inStream = null; 
     BufferedInputStream bis = null; 

     try{ 
      inStream = new FileInputStream("C:\\a.mp4"); 

      bis = new BufferedInputStream(inStream); 

      int numByte = bis.available(); 


      byte[] buf = new byte[numByte]; 
      bis.read(buf, 0, numByte); 
      System.out.println(numByte/1024); 
      ArrayList<byte[]> a = new ArrayList<>(); 
      ArrayList<byte[]> b = new ArrayList<>(); 
      for(int i=0,j=0;i<buf.length;i++,j++){ 
       byte[] buf2 = new byte[1057]; 
       buf2[j] = buf[i]; 
       if(i%1024==1023){ 
        a.add(buf2); 
        j=0; 
       } 
      } 

      for(int i=a.size()-1,j=-1;i>=0;i--,j++){ 
       MessageDigest digest = MessageDigest.getInstance("SHA-256"); 
       if(i==a.size()-1){ 
        byte[] hash = digest.digest(a.get(i)); 
        byte[] dest = new byte[a.get(i).length+hash.length]; 
        System.arraycopy(a.get(i-1), 0, dest, 0, a.get(i-1).length); 
        System.arraycopy(hash, 0, dest, a.get(i-1).length, hash.length); 
        b.add(dest); 
       } 
       else{ 
        byte[] hash = digest.digest(b.get(0)); 
        if(i!=0){ 
         byte[] dest = new byte[a.get(i-1).length+hash.length]; 
         System.arraycopy(a.get(i-1), 0, dest, 0, a.get(i-1).length); 
         System.arraycopy(hash, 0, dest, a.get(i-1).length, hash.length); 
         b.clear(); 
         b.add(dest); 
        }else{ 
         System.out.println(bytesToHex(hash));} 
       } 

      } 

     }catch(Exception e){ 
      e.printStackTrace(); 
     }finally{ 
      if(inStream!=null) 
       inStream.close(); 
      if(bis!=null) 
       bis.close(); 
     } 
    } 
    final protected static char[] hexArray = "ABCDEF".toCharArray(); 
    public static String bytesToHex(byte[] bytes) { 
     char[] hexChars = new char[bytes.length * 2]; 
     for (int j = 0; j < bytes.length; j++) { 
      int v = bytes[j] & 0xFF; 
      hexChars[j * 2] = hexArray[v >>> 4]; 
      hexChars[j * 2 + 1] = hexArray[v & 0x0F]; 
     } 
     return new String(hexChars); 
    } 
} 

我在這次嘗試中直接讀取了1KB的塊。在這種嘗試中,出於某種原因哈希需要很長時間。

package com.test; 

import java.io.BufferedInputStream; 
import java.io.FileInputStream; 
import java.io.InputStream; 
import java.security.MessageDigest; 
import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.List; 

public class ReadFileByteByByte2 { 

    public static void main(String[] args) throws Exception { 

     InputStream inStream = null; 
     BufferedInputStream bis = null; 

     try{ 
     inStream = new FileInputStream("C:\\aa.mp4"); 

     bis = new BufferedInputStream(inStream); 

     int numByte = bis.available(); 

     System.out.println(numByte/1024); 
     ArrayList<byte[]> a = new ArrayList<>(); 
     ArrayList<byte[]> b = new ArrayList<>(); 
     byte[] buf = new byte[numByte]; 
     int ii=0; 
     while(bis.read(buf, ii, 1024)!=-1){ 
       a.add(buf); 
     } 
     System.out.println(a.size()); 
     for(int i=a.size()-1,j=-1;i>=0;i--,j++){ 
      MessageDigest digest = MessageDigest.getInstance("SHA-256"); 
      if(i==a.size()-1){ 
       System.out.println(a.get(i).toString()); 
       byte[] hash = digest.digest(a.get(i)); 
       byte[] dest = new byte[a.get(i).length+hash.length]; 
       System.arraycopy(a.get(i-1), 0, dest, 0, a.get(i-1).length); 
       System.arraycopy(hash, 0, dest, a.get(i-1).length, hash.length); 
       b.add(dest); 
      } 
      else{ 
       System.out.println(i); 
       byte[] hash = digest.digest(b.get(0)); 
       if(i!=0){ 
        byte[] dest = new byte[a.get(i-1).length+hash.length]; 
        System.arraycopy(a.get(i-1), 0, dest, 0, a.get(i-1).length); 
        System.arraycopy(hash, 0, dest, a.get(i-1).length, hash.length); 
        b.clear(); 
        b.add(dest); 
       }else{ 
       System.out.println(bytesToHex(hash));} 
      } 

     } 

     }catch(Exception e){ 
      e.printStackTrace(); 
     }finally{ 
      if(inStream!=null) 
       inStream.close(); 
      if(bis!=null) 
       bis.close(); 
     } 
    } 
    final protected static char[] hexArray = "ABCDEF".toCharArray(); 
    public static String bytesToHex(byte[] bytes) { 
     char[] hexChars = new char[bytes.length * 2]; 
     for (int j = 0; j < bytes.length; j++) { 
      int v = bytes[j] & 0xFF; 
      hexChars[j * 2] = hexArray[v >>> 4]; 
      hexChars[j * 2 + 1] = hexArray[v & 0x0F]; 
     } 
     return new String(hexChars); 
    } 
} 

任何幫助真的很感激。提前致謝。

回答

2

首先,您必須使用DataInputStream.readFully()來確保您確實獲得了1k塊,並且確保在最後一個塊中的塊比其他塊短時不要使用它。不能保證填充緩衝區,或返回任何大於1的數。看到Javadoc。

其次,你錯了available().它不會做你正在使用它:它告訴你可以讀取多少個字節沒有阻塞。它不適用於EOS測試,也不適用於獲取流的長度。看到Javadoc。在這種情況下,你完全不需要它,只需要File.length().

第三,你並不需要將塊的散列附加到塊中,以便計算下一個散列。只要在塊數據上調用digest.update(),然後digest.doFinal()提供前一個散列作爲參數,並且您將得到完全相同的值。

第四,我想知道你是否正確理解了你的要求。計算正向散列值會更有意義。那麼你根本不需要把整個文件讀入內存。增加的完整性也是一樣的。

+0

嗨EJP,首先感謝您的快速回復。您建議的readFully()不適用於我,因爲我試圖散列最後一個塊,因爲它沒有任何填充。無論如何,我實施它的方式是錯誤的,我能弄明白。我無法理解摘要的update()方法,如果您可以提供一個代碼示例,那就太好了。最後,正向散列的思想對我不起作用,因爲我不使用密鑰交換,因此如果整個塊和散列都改變了,那麼用戶就無法區分這種差異。再次感謝您的快速回復。 – anirudh

+0

如上所述,您需要在最後一個塊上使用'readFully()'*除*。 'update()'方法可以在最後的'doFinal()'方法之前調用任意次數。 'digest()'方法只是一個簡寫。 – EJP

+0

噢......好吧......我想我沒有正確閱讀......謝謝.. – anirudh