3

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

我正在寻找获取类的 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[] 内容。

4

3 回答 3

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();
}
于 2013-11-15T14:50:39.817 回答
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;
    }
}
于 2013-11-15T07:58:06.840 回答
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 以用于示例 XML。MD5 的一个例子是49e6d7e2967d1a471341335c49f46c6c,一旦文件名和大小改变,md5 就会改变。您可以以 XML 格式存储每个文件的 md5,下次运行代码来检查 md5 并比较 xml 文件中每个文件的 md5。

于 2013-11-15T05:15:26.833 回答