我有一个文件缓存,从不同的网址下载文件。我想用他们的网址名称保存每个文件。这些名称可能很长,而且我在使用FAT32文件系统的设备上 - 所以在我用完实际磁盘空间之前,长名称正在耗尽资源。
我正在寻找缩短文件名的方法,得到了散列字符串的建议。但我不确定哈希是否保证两个不同的字符串是唯一的。如果两个哈希的网址出现相同的哈希值,我会意外地获取错误的图像,这将是不好的。
由于
答案 0 :(得分:5)
您可以为每个网址生成UUID,并将其用作文件名。
UUID是唯一的(或“实际上唯一的”),长度为36个字符,所以我想文件名不会有问题。
从版本5开始,JDK附带一个类来生成UUID(java.util.UUID)。如果有办法将它们与URL关联,您可以使用随机生成的UUID,或者您可以使用基于名称的UUID。基于名称的UUID始终相同,因此以下内容始终为真:
String url = ...
UUID urlUuid = UUID.nameUUIDFromBytes(url.getBytes);
assertTrue(urlUuid.equals(UUID.nameUUIDFromBytes(url.getBytes)));
答案 1 :(得分:3)
没有(缩短)散列可以保证每个输入的不同散列。这根本不可能。
我通常这样做的方法是将原始名称保存在缓存文件的开头(例如,第一行)。因此,要在缓存中查找文件,请执行以下操作:
您还可以考虑在数据库中保存URL->文件映射。
答案 2 :(得分:2)
但是我不确定哈希是否保证两个不同的字符串是唯一的。
他们非常不(因为pigeonhole principle而不能)。但是如果散列足够长(至少64位)并且分布均匀(理想情况下是加密散列),则碰撞的可能性变得非常小,以至于不值得担心。
作为一个粗略的准则,一旦文件数接近可能不同的哈希值(birthday paradox)的平方根,就会发生冲突。因此,对于64位哈希(10个字符的文件名),如果你有40亿个文件,你有大约50%的机会发生一次单一的冲突。
您必须决定这是否是可接受的风险。你可以通过延长哈希值来减少碰撞的几率,但当然在某些时候这意味着与你想要的相反。
答案 3 :(得分:1)
目前,建议使用SHA-1算法。没有已知的方法来故意引发此算法的冲突,因此您应该是安全的。引发具有共同结构的两个数据(例如http://
前缀)的冲突更加困难。如果在获得HTTP 200响应后保存这些东西,那么URL显然会获取一些东西,因此获得具有相同SHA-1哈希的两个不同的有效URL实际上不应该是一个问题。
如果有任何重新保证Git使用它来识别源代码存储库中的所有对象,提交和文件夹。我还没有听到有人在对象商店发生碰撞。
答案 4 :(得分:1)
哈希不是保证是唯一的,但碰撞的可能性很小。
如果您的哈希值是128比特,则任何条目对的冲突几率为1 ^ 2 ^ 128。在生日悖论中,如果你的表中有10 ^ 18个条目,那么碰撞的几率只有1%,所以你真的不必担心它。如果你是一个额外的偏执狂,那么使用SHA256或SHA512增加哈希的大小。
显然,您需要确保散列表示实际占用的空间比原始文件名少。 Base-64编码的字符串代表每个字符6位,因此您可以进行数学计算,以确定它是否值得首先进行哈希。
如果您的文件系统barfs因为名称太长,那么您可以为实际存储创建前缀子目录。例如,如果文件映射了哈希ABCDE,那么您可以将其存储为/path/to/A/B/CDE
,或者/path/to/ABC/DE
,具体取决于哪种方式最适合您的文件系统。
Git是这种技术在实践中的一个很好的例子。
答案 5 :(得分:1)
您可以做的是通过索引保存文件并使用索引文件来查找实际文件的位置
在您拥有的目录中:
index.txt
file1
file2
...
etc.
并在index.txt中使用一些数据结构有效地查找文件名(或用数据库替换)
答案 6 :(得分:0)
看看我的评论
一个可能的解决方案(有很多)是创建一个本地文件(SQLite?XML?TXT?),您可以在其中存储一对(file_id-file_name),以便您可以使用其唯一ID作为文件名保存下载的文件。
只是一个想法,而不是最好的......