Search code examples
javafilehashinputstreamguava

Is there any way to get the hashcode of an InputStream using Guava?


Is there a way to get the HashCode of an InputStream in Java, I am trying to upload a picture using the <p:fileUpload/> from PrimeFaces, converting it into a HashCode and comparing it to another picture.

At the moment I'm trying this:

public void save(FileUploadEvent event) throws IOException {
        HashCode hashCode = null;
        HashCode hashCodeCompare = null;
        hashCode = Files.asByteSource(new File(event.toString())).hash(Hashing.murmur3_128(50));
        hashCodeCompare = Files.asByteSource(new File(FilePathOfFileToCompare)).hash(Hashing.murmur3_128(50));
        boolean hashTrueFalse;
        if(hashCode.equals(hashCodeCompare)) {
            System.out.println("true");
        } else{
            System.out.println("false");
        }

        try (InputStream input = event.getFile().getInputstream()) {
            String imageName = generateFileName() + "." + fileExtensions(event.getFile().getFileName());
            String imageLink = PICTURE_DESTINATION + "\\" + imageName;


            Picture picture = new Picture();
            picture.setPictureUrl(imageLink);
            pictureService.createOrUpdate(picture);

            personForm.getCurrentPersonDTO().setPictureDTO(pictureMapper.toDTO(picture));


        } catch (IOException e) {
            e.printStackTrace();
        }
    }

Is there any way to turn the InputStream into a hashcode?


Solution

  • You have to read the InputStream if you are going to calculate a hash on the bytes it contains. First read the InputSteam to a byte[].

    With Guava use ByteStreams:

    InputStream in = ...;
    byte[] bytes = ByteStreams.toByteArray(in);
    

    An alternative popular way to do this is to use Commons IO:

    InputStream in = ...;
    byte[] bytes = IOUtils.toByteArray(in);
    

    Then you can call Arrays.hashCode() on the byte array:

    int hash = java.util.Arrays.hashCode(bytes);
    

    However you might consider using SHA256 as your hash function instead as you are less likely to have a collision:

    MessageDigest digest = MessageDigest.getInstance("SHA-256");
    byte[] sha256Hash = digest.digest(bytes);
    

    If you don't want to read the entire stream to an in memory byte array you can calculate the hash as the InputStream is being read by someone else. For example you might want to stream the InputStream to disk to into a db. Guava provides a class that wraps an InputStream that does this for you HashingInputStream:

    First wrap your InputStream with a HashinInputStream

    HashingInputStream hin = new HashingInputStream(Hashing.sha256(), in);
    

    Then let that HashingInputStream be read in any way you like

    while(hin.read() != -1);
    

    Then get the hash from the HashingInputStream

    byte[] sha256Hash = hin.hash().asBytes();