我正在尝试从文件夹中的所有子文件夹中获取一个随机文件。
首先,我使用以下代码获取所有文件的迭代器:
$path = "/path/to/folder";
$folder = new RecursiveDirectoryIterator($path);
$iterator = new RecursiveIteratorIterator($folder);
$files = new RegexIterator($iterator,
'/^.+.(jpg|jpeg|png|gif)$/i',
RecursiveRegexIterator::GET_MATCH);
这似乎有效(并在一瞬间完成)。现在我想从生成的迭代器中获取一个随机项目。我使用此代码(这是第 14 行):
$image = array_keys(iterator_to_array($files))[mt_rand(0,
count(iterator_to_array($files)) - 1)];
该文件夹包含334327†对象,并且在执行几秒钟后,iterator_to_array()
死亡并显示以下错误:
Fatal error: Allowed memory size of 134217728 bytes exhausted
(tried to allocate 1232 bytes) in /script.php on line 14
我需要如何更改我的代码以避免 PHP 内存不足?或者有没有更好的方法可以从如此庞大的数组中抓取随机物品?(或者甚至可以直接从所有子文件夹中获取一个随机文件?
我不想覆盖内存限制!
† 文件数量不断变化。
好的,所以我现在正在做的 - 它有效 - 不是将迭代器转换为数组,而是计算迭代器中的项目,计算一个随机数,然后循环迭代器,直到我到达具有该数字的项目:
$path = "/path/to/folder";
$folder = new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS);
$iterator = new RecursiveIteratorIterator($folder);
$files = new RegexIterator($iterator, '/^.+.(jpg|jpeg|png|gif)$/i', RecursiveRegexIterator::GET_MATCH);
$i = mt_rand(0, iterator_count($files) - 1);
$c = 0;
foreach($files as $file) {
if ($i == $c) {
$image = $file[0];
break;
}
$c++;
}
我说,这现在有效,但是:
计数大约需要 10 秒,所以我很乐意以某种方式缩写它;
foreach循环也需要几秒钟,所以如果我可以直接按编号从迭代器中检索元素,我会很高兴,但我找不到任何关于如何做到这一点的例子。
所以,如果你对如何解决1或2有想法,我将不胜感激。
听起来你正在寻找一个从数组中挑选随机元素的函数。如果数组维度已知/常量,则可以迭代 PHP array_rand()
函数。
但是,如果您的数组尺寸现在已知并根据输入(例如,文件树中的不同位置)而变化,那么事情就会变得更加复杂。幸运的是,有人在 10 年前回答了这个问题,并在 PHP 手册的评论中发布了一段截取的代码array_rand()
:
<?php
/**
* Returns a number of random elements from an array.
*
* It returns the number (specified in $limit) of elements from
* $array. The elements are returned in a random order, exactly
* as it was passed to the function. (So, it's safe for multi-
* dimensional arrays, aswell as array's where you need to keep
* the keys)
*
* @author Brendan Caffrey <bjcffnet at gmail dot com>
* @param array $array The array to return the elements from
* @param int $limit The number of elements to return from
* the array
* @return array The randomized array
*/
function array_rand_keys($array, $limit = 1) {
$count = @count($array)-1;
// Sanity checks
if ($limit == 0 || !is_array($array) || $limit > $count) return array();
if ($count == 1) return $array;
// Loop through and get the random numbers
for ($x = 0; $x < $limit; $x++) {
$rand = rand(0, $count);
// Can't have double randoms, right?
while (isset($rands[$rand])) $rand = rand(0, $count);
$rands[$rand] = $rand;
}
$return = array();
$curr = current($rands);
// I think it's better to return the elements in a random
// order, which is why I'm not just using a foreach loop to
// loop through the random numbers
while (count($return) != $limit) {
$cur = 0;
foreach ($array as $key => $val) {
if ($cur == $curr) {
$return[$key] = $val;
// Next...
$curr = next($rands);
continue 2;
} else {
$cur++;
}
}
}
return $return;
}
?>
我了解,您的脚本搜索所有子文件夹,如果总数334327是文件+文件夹的计数,那么您需要分离您的sript以获取随机路径,然后在路径中获取随机文件。换句话说,您可以构建所有子文件夹和文件的图形,并在图形中选择随机点。