Java class to compute and get a MD5 hash as a string Here is my class file to compute MD5 hashes on a file. I wanted to be able to easily calculate them without having to create a lot of overhead in the code using the class.

Can anyone tell me a list of improvements to make this class acceptable?

package Md5Generator;

/**
 *
 * @author jacob
 */
 import java.io.IOException;
 import java.security.*;
 import java.nio.file.Files;
 import java.nio.file.Paths;
 import java.nio.file.Path;

 /**
  * The point of this class it to compute the MD5 sum of a file
  */
 public class Md5 {
// two instance variables, one to store the file path and one to store the MD5 sum
private String path;
private String md5Sum;

/**
 * Constructor that takes a file path and and calcs the MD5 sum
 *
 * @param filePath the string that contains the full path to the file
 */
public Md5(String filePath) {
    path = filePath;
    calcMd5(path);
}

private void calcMd5(String filePath) {
    //create a messagedigest object to compute an MD5 sum
    try {
        MessageDigest md = MessageDigest.getInstance("MD5");
        //create a input stream to get the bytes of the file
        Path path = Paths.get(filePath);
        //read the bytes from the file and put them in the message digest
        md.update(Files.readAllBytes(path));
        //digest the bytes and generate an MD5 sum thats stored in an array of bytes
        byte[] hash = md.digest();
        //convert the byte array to its hex counter parts and store it as a string
        md5Sum = toHexString(hash);
    } catch (IOException | NoSuchAlgorithmException ex) {
        ex.printStackTrace();
    }

}

private String toHexString(byte[] bytes) {
    char[] hexArray = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
    char[] hexChars = new char[bytes.length * 2];
    int v;
    for (int j = 0; j &lt; bytes.length; j++) {
        v = bytes[j] &amp; 0xFF;
        hexChars[j * 2] = hexArray[v / 16];
        hexChars[j * 2 + 1] = hexArray[v % 16];
    }
    return new String(hexChars);
}

/**
 * Returns the MD5 sum as a String
 *
 * @return the string that contains the MD5 sum
 */
public String getMd5Sum() {
    return md5Sum;
}
}
THe most striking issue I can see in your code is that you're severely limited in the size of files you can compute the hash on. This line of code is particularly jarring:

md.update(Files.readAllBytes(path));


You read the entire file in to memory... which limits you to two things:


the size of your file is limited to the size of your memory ... unless
you have lots of memory, but the file is >2GB at which point you can't create a larger array of bytes.


The reason that the MessageDigest methods contain the update method, is to deal with larger files, and allow you to hash them in parts.

I would use this as an opportunity to learn the somewhat older NIO features: Channels, and Buffers.

Consider the code:

try (MessageDigest md = MessageDigest.getInstance("MD5")) {
    try (FileChannel fc = FileChannel.open(Paths.get(filePath))) {
        long meg = 1024 * 1024;
        long len = fc.size();
        long pos = 0;
        while (pos &lt; len) {
            long size = Math.min(meg, len - pos);
            MappedByteBuffer mbb = fc.map(MapMode.READ_ONLY, pos, size);
            md.update(mbb);
            pos += size;
        }
    } catch (IOException ioe) {
        ....
    }
    byte[] hash = md.digest();
    .....
} catch ( NoSuchAlgorithmException nsae) {
    ....
}


The advantage of the above code is that is plays much closer to the operating system. In theory, it should be the fastest possible way for a Java program to read the file, and it should never transfer the actual file content in to the Java memory space. It removes at least one data copy between the file represented in the OS on disk, and the copy in memory.

There is no limit to the size of file you compute the hash on.