【问题标题】:Read file as 1KB chunks using java使用 java 将文件读取为 1KB 块
【发布时间】:2014-02-10 03:04:10
【问题描述】:

我正在尝试从内存中读取文件并将其拆分为 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 = "0123456789ABCDEF".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 = "0123456789ABCDEF".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);
    }
}

非常感谢任何帮助。提前致谢。

【问题讨论】:

    标签: java


    【解决方案1】:

    首先,您必须使用DataInputStream.readFully() 来确保您确实获得了 1k 个块,并且如果它比其他块短,请确保不要在最后一个块上使用它。 read() 不能保证填充缓冲区,或返回任何大于一的计数。请参阅 Javadoc。

    其次,你在滥用 available(). 它并没有起到你的作用:它告诉你可以读取多少字节没有阻塞。它作为一个无效的EOS测试,也不是作为获取流长度的手段。请参阅 Javadoc。在这种情况下你根本不需要它,只需File.length().

    第三,您实际上不需要将块的哈希附加到块上,以便计算下一个哈希。只需在块数据上调用digest.update(),然后digest.doFinal() 提供以前的哈希作为参数,您将得到完全相同的值。

    第四,我想知道您是否正确理解了您的要求。计算正向的哈希值会更有意义。然后,您根本不需要将整个文件读入内存。增加的完整性是相同的。

    【讨论】:

    • 您好 EJP,首先感谢您的快速回复。您建议的 readFully() 对我不起作用,因为我正在尝试按原样散列最后一个块,而没有任何填充。无论如何,我实施它的方式是错误的,我能够弄清楚。我无法理解摘要的 update() 方法,如果您可以为此提供代码示例,那就太好了。最后,正向散列的想法对我不起作用,因为我没有使用密钥交换,因此如果整个块和散列被更改,那么用户无法区分。再次感谢您的快速回复。
    • 你需要在最后一个块上使用readFully() except,正如我上面所说的。 update() 方法可以在最终的doFinal() 方法之前调用任意次数。 digest() 方法只是一个简写。
    猜你喜欢
    • 1970-01-01
    • 2015-07-07
    • 2012-03-24
    • 1970-01-01
    • 1970-01-01
    • 2011-07-27
    • 2017-01-17
    • 2012-01-05
    • 1970-01-01
    相关资源
    最近更新 更多