计算Java类的校验和的最佳方法是什么?

时间:2013-11-15 04:59:15

标签: java class reflection checksum

我有一个应用程序,我正在基于Java“源”类生成“目标文件”。我想在源更改时重新生成目标。我已经决定最好的方法是获取类内容的byte []并计算byte []的校验和。

我正在寻找获得类的byte []的最佳方法。此byte []将等同于已编译的.class文件的内容。使用ObjectOutputStream 工作。下面的代码生成一个byte [],它比类文件的字节内容小得多。

// Incorrect function to calculate the byte[] contents of a Java class
public static final byte[] getClassContents(Class<?> myClass) throws IOException {
    ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    try( ObjectOutputStream stream = new ObjectOutputStream(buffer) ) {
        stream.writeObject(myClass);
    }
    // This byte array is much smaller than the contents of the *.class file!!!
    byte[] contents = buffer.toByteArray();
    return contents;
}

有没有办法让byte []具有* .class文件的相同内容?计算校验和是很容易的部分,困难的部分是获取用于计算MD5或CRC32校验和的byte []内容。

3 个答案:

答案 0 :(得分:4)

这是我最终使用的解决方案。我不知道它是否是最有效的实现,但是下面的代码使用类加载器来获取* .class文件的位置并读取其内容。为简单起见,我跳过了缓冲读取。

// Function to obtain the byte[] contents of a Java class
public static final byte[] getClassContents(Class<?> myClass) throws IOException {
    String path = myClass.getName().replace('.', '/');
    String fileName = new StringBuffer(path).append(".class").toString();
    URL url = myClass.getClassLoader().getResource(fileName);
    ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    try (InputStream stream = url.openConnection().getInputStream()) {
        int datum = stream.read();
        while( datum != -1) {
            buffer.write(datum);
            datum = stream.read();
        }
    }   
    return buffer.toByteArray();
}

答案 1 :(得分:0)

我不明白你的意思,但我认为你正在寻找这个,MD5。

要检查文件的MD5,您可以使用此代码

public String getMd5(File file)
{
    DigestInputStream stream = null;
    try
    {
        stream = new DigestInputStream(new FileInputStream(file), MessageDigest.getInstance("MD5"));
        byte[] buffer = new byte[65536];

        read = stream.read(buffer);
        while (read >= 1) {
        read = stream.read(buffer);
        }
    }
    catch (Exception ignored)
    {
        int read;
        return null;
    }
    return String.format("%1$032x", new Object[] { new BigInteger(1, stream.getMessageDigest().digest()) });
}

然后,您可以以任何方式存储文件的md5以用于exmaple XML。 MD5的例子是49e6d7e2967d1a471341335c49f46c6c,因此一旦文件名和大小发生变化,md5就会改变。您可以以XML格式存储每个文件的md5,下次运行代码以检查md5并比较xml文件中每个文件的md5。

答案 2 :(得分:0)

如果你真的想要.class文件的内容,你应该读取.class文件的内容,而不是内存中的byte []表示。像

这样的东西
import java.io.*;

public class ReadSelf {
    public static void main(String args[]) throws Exception  {
        Class classInstance = ReadSelf.class;
        byte[] bytes = readClass(classInstance);
    }
    public static byte[] readClass(Class classInstance) throws Exception {
        String name = classInstance.getName();
        name = name.replaceAll("[.]", "/") + ".class";
        System.out.println("Reading this: " + name);
        File file = new File(name);
        System.out.println("exists: " + file.exists());
        return read(file);
    }
    public static byte[] read(File file) throws Exception {
        byte[] data = new byte[(int)file.length()]; // can only read a file of size INT_MAX
        DataInputStream inputStream =
        new DataInputStream(
            new BufferedInputStream(
                new FileInputStream(file)));

        int total = 0;
        int nRead = 0;
        try {
            while((nRead = inputStream.read(data)) != -1) {
                total += nRead;
            }
        }
        finally {
            inputStream.close();
        }
        System.out.println("Read " + total
            + " characters, which should match file length of "
            + file.length() + " characters");
        return data;
    }
}
相关问题