【问题标题】:Can you SHA1 hash a file to a certain length您可以将文件 SHA1 散列到一定长度吗
【发布时间】:2018-01-24 08:38:09
【问题描述】:

我需要比较两个文件。一个文件可能比另一个文件长,我需要检查较长的文件是否包含较短文件的所有数据。 我可以对两者进行二进制比较,如下所示:

function compareFiles($file_a, $file_b){
  if (filesize($file_a) > filesize($file_b)){
    $fp_a = fopen($file_b, 'rb');
    $fp_b = fopen($file_a, 'rb');
  } else { // filesize($file_b) > filesize($file_a)
    $fp_a = fopen($file_a, 'rb');
    $fp_b = fopen($file_b, 'rb');
  }
  while (($b = fread($fp_a, 4096)) !== false){
    $b_b = fread($fp_b, 4096);
    if ($b !== $b_b){
      fclose($fp_a);
      fclose($fp_b);
      return false;
    }
  }
  fclose($fp_a);
  fclose($fp_b);
  return true;
}

但这会很慢。作为替代方案,我可以将较小文件的 SHA1 哈希值与较大文件的 SHA1 哈希值进行比较,直到较小文件的大小,如下所示:

function compareFiles($file_a, $file_b){
  $tmpfile = '/dev/shm/tmp_file_copy.bin';
  if (filesize($file_a) > filesize($file_b)){
    $readfromfile = $file_b;
    $bytes_to_copy = filesize($file_b);
  } else {
    $readfromfile = $file_a
    $bytes_to_copy = filesize($file_a);
  }
  $readfile = fopen($readfromfile, 'rb');
  $writefile = fopen($tmpfile, 'wb');
  while (!feof($readfile) && $bytes_to_copy> 0) {
    if ($bytes_to_copy <= 8192) {
      $contents = fread($readfile, $bytes_to_copy);
      $bytes_to_copy = 0;
    } else {
      $contents = fread($readfile, 8192);
      $bytes_to_copy =- 8192;
    }
    fwrite($writefile, $contents);
  }
  fclose($writefile);
  fclose($readfile);
  $result = sha1_file($readfromfile = $file_a ? $file_b : $file_a) === sha1_file($tmpfile);
  unlink($tmpfile);
  return $result;
}

但我担心这也会很慢,因为它涉及大量 I/O(到 /dev/shm)。

简而言之,我正在寻找更好的方法......

【问题讨论】:

  • 比较所需的输出是什么?
  • 输出是真还是假。不超过较短文件长度的文件内容匹配或不匹配。
  • 您可以使用 fread 将整个文件获取到字节 X 以进行比较,您不需要将其循环成块
  • 是的,但在我看来,将其分块更安全。我也可以在那里添加重试,但这会变得更复杂,并从问题的角度误导读者。

标签: php hash sha


【解决方案1】:

在这种情况下散列文件只会更慢。考虑以下情况。

文件A.txt内容:

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

文件B.txt内容:

AAAAAAAAAAAAAAAAAAAAABBBBBBBBBB

请注意,A.txt 总共 40 个字符,比 B.txt 长 10 个字符,共 30 个字符

我们必须对每个文件执行多少 I/O 才能确定 A.txt 是否包含所有 B.txt? 40字节? 30字节?不,答案只有 20 个字节,因为这就是两个文件共享的共同点。您一次流式传输每个文件一个字节(或字节块),并随时比较它们。这种比较的结果如下所示:

A.txt: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

B.txt: AAAAAAAAAAAAAAAAAAAAABBBBBBBBBB

Stream ---------------------^
Result ✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓X

然后你停下来。为什么要比较其余的?

如果您对两个文件进行哈希处理,则必须将全部内容保存在内存中才能计算哈希值。即使您在将它们流式传输到内存时将它们散列成块,您认为哪个更快:比较每个文件中的每个字节还是散列块?比较的复杂度为O(number of bytes),而SHA-1 哈希算法的复杂度由RFC 3174 指定。

【讨论】:

  • 是的,我同意 compareFiles 会更有效,因为它会在达到较小文件的文件大小或文件不同的地方停止比较。谢谢! :)
  • 很高兴您喜欢@Greg 的答案。如果您满意,请按绿色复选标记接受。
【解决方案2】:

在您的情况下,逐字节是最好的方法。它只比较两个文件的前 x 个字节,如果它们不同则停止。哈希函数必须处理文件中的所有字节。那不是更慢吗?

【讨论】:

    猜你喜欢
    • 2015-05-03
    • 2021-02-06
    • 2017-12-26
    • 2016-08-10
    • 1970-01-01
    • 2019-02-26
    • 1970-01-01
    • 2023-03-24
    • 1970-01-01
    相关资源
    最近更新 更多