如何提高 PHP 中 for 循环的速度?

我有一个包含不同行的 CSV 文件:

;0;1;0;4;5;M;468468;A1101;00900;1;
0;4;5;M;468468;A1108;0090

例如,在照片文件夹中,第一个视图的命名格式必须为“A1101_0090-1.JPG”。

我写了一段代码,它可以让你做两件事:

  • csv 文件和照片文件夹中存在的图像的名称以及视图数

  • 照片文件夹中但不在 csv 文件中或被错误重命名的图像的名称。

我的脚本可以工作,但是当我放置一个包含超过 5000 张照片的大照片文件夹时,处理时间非常长......我该如何改进我的代码?

<?php

echo '<pre>';

$dataImage = [];

$dataImageTmp = [];

$path = $_POST['path'];


$photos = scandir($path);

$photos = array_map('strtoupper', $photos);


if (($handle = fopen("../RC_PRODUCT_HUB.csv", "r")) !== FALSE) {

    $firstLine = true;

    while (($data = fgetcsv($handle, 9000000, ";")) !== FALSE){

        if (!$firstLine){

            if ($data[0] != null) {

                $countImage = count(glob($path . $data[6] . '_' . $data[7] . '*.*'));

                for ($i = 0; $i <= $countImage; ++$i) {

                    if ((file_exists($fileName = $path.$data[6].'_'.$data[7].'-'.$i.'.JPG'))){

                        if (!in_array($fileName, $dataImage)){

                            $dataImage[$data[6] . '_' . $data[7]]['file'][$i] = $fileName;

                            $fileName = str_replace($path, '', $fileName);

                            if (!in_array($fileName, $dataImageTmp)){

                                $dataImageTmp[] = $fileName;

                            }

                        }

                        $dataImage[$data[6] . '_' . $data[7]]['TOTAL'] = $countImage;

                    }

                }

            }

        }

        $firstLine = false;

    } 


    //FIRST PART

    echo count($dataImage)." refs founds.<br>";

    print_r($dataImage).'<br>';


    //SECOND PART


    $dataImageTmp = array_map('strtoupper', $dataImageTmp); 

    $resultat = array_diff($photos, $dataImageTmp);

    $element = '.';

    unset($resultat[array_search($element, $resultat)]);

    $element2 = '..';

    unset($resultat[array_search($element2, $resultat)]);


    echo count($resultat)." photos found.<br>";


    foreach ($resultat as $result) {

        echo ($result) . '<br>';

    }

}

?>


子衿沉夜
浏览 153回答 2
2回答

大话西游666

别打电话glob()。只需使用一个循环来处理按数字顺序匹配模式的每个文件。当文件不存在时,您可以停止循环。我假设您的文件名数字序列中没有间隙。if (($handle = fopen("../RC_PRODUCT_HUB.csv", "r")) !== FALSE) {&nbsp; &nbsp; fgets($handle); // skip header line&nbsp; &nbsp; while (($data = fgetcsv($handle, 9000000, ";")) !== FALSE){&nbsp; &nbsp; &nbsp; &nbsp; if ($data[0] != null) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for ($i = 1; file_exists($fileName = $path.$data[6].'_'.$data[7].'-'.$i.'.JPG'); ++$i) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (!in_array($fileName, $dataImage)){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $dataImage[$data[6] . '_' . $data[7]]['file'][$i] = $fileName;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $fileName = str_replace($path, '', $fileName);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (!in_array($fileName, $dataImageTmp)){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $dataImageTmp[] = $fileName;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (isset($dataImage[$data[6] . '_' . $data[7]]['TOTAL'])) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $dataImage[$data[6] . '_' . $data[7]]['TOTAL']++;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $dataImage[$data[6] . '_' . $data[7]]['TOTAL'] = 1;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}&nbsp;

Helenr

需要注意的一些事项:为什么先count(glob(..))循环查找文件名( file_exists)?您只需glob($path . $data[6] . '_' . $data[7] . '*.JPG')获取文件名即可。您的解决方案首先创建一个所有文件名的数组,对其进行计数,然后丢弃它并为文件名创建一个全新的数组。您可以迭代 返回的数组glob,然后$i根据需要从文件名中提取。如果需要count(glob(..)),可以用 shell 命令替换它。我认为它们会更快,因为它们不需要 PHP 中的内存分配/释放。类似的东西shell_exec("ls '{$path}{$data[6]}_{$data[7]}*.*' | wc -l")。当然,这是针对基于 *nix 的系统和bash/sh. 您可以在其他操作系统(或 shell)中找到类似的东西。您可以以某种方式分割文件,并使用多个脚本来处理它们。该解决方案可能会有很大差异,具体取决于您想要的复杂程度。喜欢:预先拆分 csv 文件,然后对其运行脚本,然后合并结果。编写一个脚本来读取 csv 并运行多个进程,将 csv 文件的某些部分交给每个进程进行处理,然后合并结果。流程或类似的库在这里可能很有用。使用作业队列。脚本读取 csv 文件并为每一行(也许不是每一行,而是每 100 行)创建一个作业。作业由多个工作人员处理,结果保存在数据库或其他内容中以进行合并。有一些解决方案,但我只在 Laravel 或 Symfony 等有自己的作业队列的框架中使用它们。搜索一下php job queue,你会找到一些解决方案。
打开App,查看更多内容
随时随地看视频慕课网APP