有没有办法使用 Guava 获取 InputStream 的哈希码?
Posted
技术标签:
【中文标题】有没有办法使用 Guava 获取 InputStream 的哈希码?【英文标题】:Is there any way to get the hashcode of an InputStream using Guava? 【发布时间】:2019-06-12 20:18:42 【问题描述】:有没有办法在 Java 中获取 InputStream 的 HashCode,
我正在尝试使用 PrimeFaces 中的<p:fileUpload/>
上传图片,将其转换为 HashCode 并将其与另一张图片进行比较。
目前我正在尝试这个:
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();
有什么方法可以将InputStream
变成哈希码?
【问题讨论】:
等等,你是要获取流的HashCode还是图像的HashCode?你当然可以通过调用.hashCode()
来获取任何Java 对象的HashCode,但更重要的是int 代表什么以及为什么要使用它。
我尝试上传一张图片,并将其转为hashvalue,并与另一张图片进行比较,看是否已经存在。我尝试使用.hashCode()
,但如果我尝试将相同的图像与输入流和文件进行比较,它会给我一个不同的 hashCode
如果您尝试使用 HashCode 来比较图像,如果图像是 JPG 或其他使用有损压缩存储的图像怎么办?图像文件位可能完全不同,但图像本身在功能上可能相同。
那么,您首选的比较图片上传和实际图片的方法是什么?我只需要一些来自外部的 iedeas/输入,因为我现在在这个问题上工作了 2.5 小时 D:
将 InputStream 读入 byte[] 然后在字节数组上运行哈希函数。您可能不想为此使用 hashCode() 。请改用 SHA256。
【参考方案1】:
我建议使用Files.asByteSource(fileSource.getFile()).hash(hashFunction).padToLong()
【讨论】:
【参考方案2】:如果要计算其包含的字节的哈希值,则必须读取 InputStream。首先将 InputSteam 读取到 byte[]。
在 Guava 中使用 ByteStreams:
InputStream in = ...;
byte[] bytes = ByteStreams.toByteArray(in);
另一种流行的方法是使用Commons IO:
InputStream in = ...;
byte[] bytes = IOUtils.toByteArray(in);
然后你可以在字节数组上调用Arrays.hashCode():
int hash = java.util.Arrays.hashCode(bytes);
但是,您可能会考虑使用 SHA256 作为哈希函数,因为您不太可能发生冲突:
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] sha256Hash = digest.digest(bytes);
如果您不想将整个流读取到内存字节数组中,您可以在其他人读取 InputStream 时计算哈希值。例如,您可能希望将 InputStream 流式传输到磁盘到数据库中。 Guava 提供了一个封装了 InputStream 的类,它会为您执行此操作HashingInputStream:
首先用 HashinInputStream 包装你的 InputStream
HashingInputStream hin = new HashingInputStream(Hashing.sha256(), in);
然后让 HashingInputStream 以你喜欢的任何方式读取
while(hin.read() != -1);
然后从 HashingInputStream 中获取哈希
byte[] sha256Hash = hin.hash().asBytes();
【讨论】:
【参考方案3】:你想要做的是ByteStreams.copy(input, Funnels.asOutputStream(hasher))
,其中hasher
是从例如获取的。 Hashing.sha256().newHasher()
。然后,调用hasher.hash()
得到结果HashCode
。
【讨论】:
我不知道为什么这没有更多的赞成票,大多数其他解决方案都需要将输入流复制到一个字节[],或者在哈希器之外循环输入流。 ByteStreams.copy(in, out) 正在为您循环输入流。使用此解决方案的缺点是您将哈希器用作接收器。因此,当您散列它们时,您会丢失字节。这通常是不可取的,例如您正在处理用户刚刚上传的输入流。你们都想将字节传递到存储中并生成哈希。但是这里的字节会在从 InputStream 中读取时丢失。 @bhspencer:老实说,实际上在大多数情况下,我实际上并不想保留字节。以上是关于有没有办法使用 Guava 获取 InputStream 的哈希码?的主要内容,如果未能解决你的问题,请参考以下文章
面试专栏Guava - ListenableFuture,避免Future获取阻塞问题,增加回调