在PHP中,file_exists()函数速度太慢了。有没有人能提供一个更快的替代方案?

45

在我们网站上显示图片时,我们使用 file_exists() 来检查文件是否存在。如果文件不存在,我们将使用一个虚拟图片。

然而,分析表明这是生成我们的页面最慢的部分之一,file_exists() 每个文件需要 1/2 毫秒 的时间。虽然我们只测试了大约40个文件,但这仍然使页面加载时间增加了20毫秒

有谁能想出一种更快的方法吗? 是否有更好的方法来测试文件是否存在?如果我建立一个缓存,如何保持它同步。


71
如果你的代码中最慢的部分仅添加了20毫秒的总加载时间,那么你应该出去喝一杯啤酒,而不是担心它到了发帖询问的程度。;-) - Duroth
2
你使用的是哪个文件系统?- file_Exists() 函数的速度应该主要取决于 stat() 系统调用的速度。目录中有多少个文件?(根据文件系统,文件数量对 stat() 速度有影响) - johannes
2
每个文件的存在检查只需要0.5毫秒,您可以在一秒钟内完成2000次。 - Adam Hopkinson
34
哦,引用维基百科……眨眼的平均时间为300至400毫秒。不确定为什么,但感觉与你分享这个信息很合适。 - Duroth
1
目录中有很多文件(数千个),这可能对性能的影响比其他任何因素都更大。我可能会考虑将其拆分成小批量的文件。 - Rik Heywood
显示剩余4条评论
20个回答

2
在2021年,自问题提出以来已经过去了12年,我有同样的用例。我对这里的答案不满意,所以进行了一个实验。我使用`file_exist`循环检查大约40张图像是否存在于文件夹中的图像中。
以下是毫秒级的数字(PHP 7.4):
- 本地开发机 (Win10, WAMP, Samsung SSD, Intel 3.4GHz):每张图像约0.1毫秒(1/10),文件夹中大约有1000张图像; - 服务器(相当基础的廉价服务器,VPS 1 Intel Xeon, RAM 2GB, SSD, Ubuntu, LAMP):每张图像约0.01毫秒(1/100),文件夹中有14,000张图像;
服务器比开发机快10倍,并且在整体用户体验性能方面几乎无法区分,30-50毫秒是可以察觉到的阈值。
在服务器上,检查包含40张图像的数组,花费了0.4毫秒来检查它们是否存在。顺便说一下,无论这些图像中是否有一些存在,性能都没有差异。
所以这个问题应该没有疑问,是否要检查file_exist,因为涉及到磁盘性能。根据需要进行检查。

1
如果你想检查图像文件是否存在,一个更快的方法是使用getimagesize

本地和远程都更快!
if(!@GetImageSize($image_path_or_url)) // False means no imagefile
 {
 // Do something
 }

1

它们都在同一个目录下吗?如果是的话,获取文件列表并将其存储在哈希表中进行比较可能比进行所有file_exists查找更值得。


我假设这个哈希值会被存储在APC或其他一些共享内存中。 - Powerlord

0

我来到这个页面寻找解决方案,看起来fopen可能是个好办法。如果你使用这段代码,你可能想要禁用未找到文件的错误日志记录。

<?php
for ($n=1;$n<100;$n++){
clearstatcache();
$h=@fopen("files.php","r");
if ($h){
echo "F";
fclose($h);
}else{
echo "N";
}
}
?>

0

6
与file_exists()相比,glob()已经过时了!我认为它在这种情况下不会有所帮助。 - Pekka

0

我认为每次调用1/2毫秒非常非常实惠。我认为没有更快的替代方案,因为文件函数非常接近处理文件操作的底层。

但是,您可以编写一个包装器来缓存file_exists()的结果到memcache或类似的设施中。这应该会在日常使用中将时间减少到几乎为零。


0

你可以使用cronjob定期创建图像列表并将它们存储在DB/file/BDB/...中。

每半个小时应该足够了,但一定要创建一个接口来重置缓存以防文件添加/删除。

然后,在shell上运行find . -mmin -30 -print0也很容易,并添加新文件。


0

我认为最好的方法是将图片URL保存在数据库中,然后将其放入会话变量中,特别是在进行身份验证时。这样你就不必每次重新加载页面时都进行检查。


0

当您将文件保存到文件夹中时,如果上传成功,您可以将路径存储到数据库表中。

然后,您只需查询数据库以查找所请求文件的路径。


数据库也通常存储在磁盘上,你确定这样会更快吗? - aland

-1

我甚至不确定这样做是否会更快,但看起来你仍然想要进行基准测试:

构建一个大型图像路径数组的缓存。

$array = array('/path/to/file.jpg' => true, '/path/to/file2.gif' => true);

根据您的需求,每小时或每天使用cron运行PHP脚本更新缓存。该脚本将递归遍历文件目录以生成路径数组。

当您希望检查文件是否存在时,请加载缓存数组并进行简单的isset()检查,以进行快速的数组索引查找:

if (isset($myCachedArray[$imgpath])) {
    // handle display
}

仍会有加载缓存的开销,但希望足够小以保持在内存中。如果您在页面上检查多个图像,则可能会注意到更显着的增益,因为您可以在页面加载时加载缓存。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接