我正在尝试从文件夹中的所有子文件夹中获取随机文件。
首先,我使用以下代码获取所有文件的迭代器:
$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耗尽内存?或者是否有更好的方法从这么庞大的数组中获取随机项? (或者甚至可以直接从所有子文件夹中获取随机文件?)
我不想要override the memory limit!
†文件数量不断变化。
答案 0 :(得分:1)
好吧,所以我现在正在做的 - 它的工作原理 - 不是将迭代器转换为数组,而是计算迭代器中的项目,计算一个随机数,然后遍历迭代器直到我到达带有该号码的项目:
$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-loop也需要几秒钟,所以如果我能用数字直接从迭代器中检索一个元素,我会很高兴,但是我找不到任何关于如何这样做。
所以,如果您对如何解决1或2有所了解,我将不胜感激。
答案 1 :(得分:0)
听起来你正在寻找一个从数组中选取一个随机元素的函数。如果数组维度已知/常量,则可以迭代PHPs array_rand()
function。
但是,如果您的数组维度现在已知并且根据输入(,例如,文件树中的其他位置)而更改,则事情会变得更复杂。幸运的是,10年前有人回答了这个问题,并在PHP manual for 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;
}
?>
答案 2 :(得分:0)
据我所知,您的脚本搜索所有子文件夹,如果总计数334327是文件+文件夹的数量,那么您需要将您的sript分开以获取随机路径然后获取路径中的随机文件。换句话说,您可以构建所有子文件夹和文件的图形,并在图形中选择随机点。