【问题标题】:Can I use file_get_contents() to compare two files?我可以使用 file_get_contents() 比较两个文件吗?
【发布时间】:2010-06-17 08:41:13
【问题描述】:

我想同步两个目录。我使用

file_get_contents($source) === file_get_contents($dest)

比较两个文件。这样做有什么问题吗?

【问题讨论】:

  • 如果文件通过服务器上的一个进程,也许这些进程可以在每次添加或修改文件时生成一个哈希,这样你只需要比较哈希就知道要同步什么

标签: php


【解决方案1】:

我宁愿做这样的事情:

function files_are_equal($a, $b)
{
  // Check if filesize is different
  if(filesize($a) !== filesize($b))
      return false;

  // Check if content is different
  $ah = fopen($a, 'rb');
  $bh = fopen($b, 'rb');

  $result = true;
  while(!feof($ah))
  {
    if(fread($ah, 8192) != fread($bh, 8192))
    {
      $result = false;
      break;
    }
  }

  fclose($ah);
  fclose($bh);

  return $result;
}

这会检查文件大小是否相同,如果是,则逐步遍历文件。

  • 在某些情况下,检查修改时间检查可能是一种快速的方法,但它并不能真正告诉您文件已在不同时间被修改过的任何信息。它们可能仍然具有相同的内容。
  • 使用 sha1 或 md5 可能是个好主意,但这需要遍历整个文件来创建该哈希。如果这个哈希值可以被存储并在以后使用,那可能就另当别论了,但是是的......

【讨论】:

  • 这在我看来是最全面的做事方式。一开始的文件大小检查将立即捕获大多数更改,甚至不需要读取文件,而且您不仅还消除了散列两个整个文件的开销,而且它会立即停止读取它发现了不同!
  • 您的代码示例是伪造的,因为它没有正确检查两个文件的 EOF。如果 $bh 大于 $ah,你可能会得到 TRUE。
  • @AlexisWilke:想详细说明一下吗?如果$bh 大于$ah,它不是已经返回了false 几行吗?
  • 我的错,你先比较尺寸!所以循环不需要考虑到这一点......
  • 我运行了一个快速基准测试,这绝对是计算文件差异的更快方法,即使文件在最后一个字节之前都是相同的。
【解决方案2】:

请改用sha1_file()。如果您只需要查看文件是否不同,它会更快并且工作正常。如果文件很大,则将整个字符串相互比较可能会非常繁重。由于sha1_file() 返回文件的 40 个字符表示,比较文件会非常快。

您也可以考虑其他方法,例如比较 filemtime 或文件大小,但即使只有一点点更改,这也能保证结果。

【讨论】:

  • sha1_file() 必须散列整个文件。当然它并不比手动比较快。
  • @Oli,我假设散列文件并将 40 个字符与其他 40 个字符进行比较比将整个文件内容相互比较要快。
  • 我不确定这是一个公平的假设。假设您有两个文件,长度为 2M 字符,并且第一个字符不同。散列会读取 4M 个字符,构建两个散列,然后比较 1 到 40 个字符(取决于散列的相似性)。直接比较将读取 2 个字符并返回。极端情况,但如果文件相等,直接比较总是会读取更少的数据。
  • 这取决于你用它做什么。如果您只是比较两个随机文件,那么my answer 的效率要高得多。但是,如果您要经常进行这些比较并且,您可以存储该哈希并在以后重用它(因此您只需检查每个文件一次),然后进行哈希可能会更好。
  • sha1_file 不是更快但更节省内存,我对 1.2MB 文件进行了测试,file_get_contents 快了 3.7 倍,但 sha1_file 仅使用了 file_get_contents 使用的内存的 5% 比较
【解决方案3】:
  • 内存:例如您有 32 MB 的内存限制,每个文件为 20 MB。尝试分配内存时出现不可恢复的致命错误。这可以通过小部分检查文件来解决。
  • 速度:字符串比较并不是世界上最快的事情,计算 sha1 哈希应该更快(如果你想 110% 确定,你可以在哈希匹配时逐字节比较文件,但是你'将排除所有内容和哈希发生变化的情况(99% 以上的情况))
  • 效率:做一些初步检查 - 例如。如果两个文件的大小不同,那么比较它们是没有意义的。

【讨论】:

  • +1 用于文件大小检查。不过,如果有文本文件,请注意自动换行,这可能很麻烦。
  • @Boldewyn:好点——Windows 行尾是 2 个字节,UNIX/Mac 是 1 个字节。但是,在这种情况下,这意味着其中一个文件被更改(FTP 除外,它会发生各种疯狂的事情)。
  • 这正是问题所在。如果其中一个文件夹位于进行行尾转换的管道的另一端,则所有文本文件将始终不同。
  • 如果有东西在做换行符,那么我宁愿研究修复那个。如果两个文件除了行尾是相同的,那么在我看来它们仍然应该被认为是不同的。
  • @Svish:当然。不幸的是,FTP 协议(​​此类问题的常见罪魁祸首)出于神秘的原因拒绝消亡 - 尽管它不安全且充满了奇怪的怪癖。
【解决方案4】:

这会起作用,但本质上比计算两个文件的校验和并比较它们效率低下。适合校验和算法的候选者是 SHA1 和 MD5。

http://php.net/sha1_file

http://php.net/md5_file

if (sha1_file($source) == sha1_file($dest)) {
    /* ... */
}

【讨论】:

    【解决方案5】:

    好像有点重。这会将两个文件完全加载为字符串,然后进行比较。

    我认为您最好手动打开这两个文件并检查它们,也许只是先检查文件大小。

    【讨论】:

      【解决方案6】:

      你在这里做的事情没有任何问题,接受它有点低效。获取每个文件的内容并进行比较,尤其是对于较大的文件或二进制数据,您可能会遇到问题。

      我会看看filetime(上次修改)和filesize,并运行一些测试看看它是否适合你。它应该是您所需的全部计算能力的一小部分。

      【讨论】:

        【解决方案7】:

        首先检查明显的:

        1. 比较尺寸
        2. 比较文件类型(mime-type)。
        3. 比较内容

        (将日期、文件名和其他元数据的比较添加到这个明显的列表中,如果它们也不应该相似的话)。

        在比较内容散列时,听起来像@Oli says in his comment 这样的效率不是很高。 如果文件不同,它们很可能在开始时就已经不同了。计算两个 50 Mb 文件的哈希值,然后比较哈希值听起来像是浪费时间,如果第二个位已经不同......

        检查this post on php.net。看起来与that of @Svish 非常相似,但它也比较文件mime-type。如果你问我,这是一个聪明的补充。

        【讨论】:

          【解决方案8】:

          我注意到缺少 N!因素。换句话说 - 要执行 filesize() 函数,您首先必须对照所有其他文件检查每个文件。为什么?如果第一个文件和第二个文件大小不同但第三个文件大小相同怎么办。

          所以首先 - 你需要得到一个你将要使用的所有文件的列表如果你想做文件大小类型的事情 - 然后使用 COMPLETE / 字符串作为数组的键,然后存储文件大小()信息。然后对数组进行排序,使所有大小相同的文件排成一行。然后你可以检查文件大小。但是 - 这并不意味着它们真的是相同的 - 只是它们的大小相同。

          您需要执行 sha1_file() 命令之类的操作,并像上面一样创建一个数组,其中键是 / 名称是键,值是返回的值。对它们进行排序,然后简单地遍历存储要测试的 sha1_file() 值的数组。那么A == B吗?是的。进行任何其他测试,然后删除 SECOND 文件并继续。

          我为什么要评论?我正在解决同样的问题,我刚刚发现我的程序无法正常工作。所以现在我要使用 sha1_file() 函数来纠正它。 :-)

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-03-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-01-31
            相关资源
            最近更新 更多