【问题标题】:Filter directorie(s) from RecursiveDirectoryIterator从 RecursiveDirectoryIterator 过滤目录
【发布时间】:2015-11-24 15:18:02
【问题描述】:

因此,为了了解更多有关 Android 开发的知识,在学习 Java 编程书籍时,我遇到了 JSONObject 和 JSONArray。 经过一番研究,我编写了一个 php 脚本来读取目标目录的内容,输出是一个 JSON 文件,其中包含足够的信息来解析我的学习资料中的 Java 类。

唯一的问题是,我接触 php 已经有好几年了,我从几个来源汇总的部分是我唯一能理解的部分 - 所以情况如下:

如何从我的结果中过滤掉(在将它们添加到我的 JSON 文件之前)排除数组(文件和/或目录),例如:“@eaDir”、“Thumbs.db”、“.DS_File”等。

这里是有问题的代码:

#!/usr/bin/php
<?php

/* Run with: php [filename].php /path/to/folder/
    Outputs file_list.json in target folder */

// Where are we running on?
if (PHP_SAPI === 'cli') {
    $argument1 = $argv[1];
    $argument2 = $argv[2];
}
else {
    $argument1 = $_GET['argument1'];
    $argument2 = $_GET['argument2'];
}

// Set output dir and file
$out = $argument1 . '/file_list.json';

/*
 * @param Array $types
 * @abstract Array of allowed file types
 */
$types = Array ('mp3', 'ogg');

if (!isset($argv[1]))
    exit("Must specify a directory to scan\n");

if (!is_dir($argv[1]))
    exit($argv[1]."' is not a directory\n");

/*
 * @name getList
 * @param Array $dir
 * @param Array $types
 * @abstract Recursively iterates over specified directory
 *           populating array based on array of file extensions
 * @return Array $files
 */
function getList($dir, $types) {
    $it = new RecursiveDirectoryIterator($dir);
    foreach(new RecursiveIteratorIterator($it) as $file) {
        if (in_array(strtolower(array_pop(explode('.', $file))), $types)) {
            $files[] = $file->__toString();
        } 
    }
    return $files; 
}

/*
 * @name getDetails
 * @param Array $dir
 * @param Array $types
 * @abstract Recursively iterates over specified directory
 *           populating array with details of each file
 * @return Array $files
 */
function getDetails($types, $array)
{
    foreach($types as $type)
    {
        foreach($array as $file)
        {
            if (strcasecmp($type, array_pop(explode('.', $file))) == 0) {
                $files[$type][basename($file)];
                $files[$type][basename($file)]['source'] = $file;
                $files[$type][basename($file)]['size'] = filesize($file);
            }
        }
    }
    return array('files'=>$files);
}

if (!function_exists('json_encode')) {

    /*
     * @name json_encode
     * @param Mixed $val
     * @abstract Alternate emulated json_encode function
     * @return Object $res
     */
    function json_encode($val)
    {
        if (is_string($val)) return '"'.addslashes($val).'"';
        if (is_numeric($val)) return $val;
        if ($val === null) return 'null';
        if ($val === true) return 'true';
        if ($val === false) return 'false';

        $assoc = false;
        $i = 0;
        foreach ($val as $k=>$v){
            if ($k !== $i++){
                $assoc = true;
                break;
            }
        }
        $res = array();
        foreach ($val as $k=>$v){
            $v = json_encode($v);
            if ($assoc){
                $k = '"'.addslashes($k).'"';
                $v = $k.':'.$v;
            }
            $res[] = $v;
        }
        $res = implode(',', $res);
        return ($assoc)? '{'.$res.'}' : '['.$res.']';
    }
}

/* Open file in write mode */
$fp = fopen($out, 'w');

/* Run application & save file */
fwrite($fp, json_encode(getDetails($types, getList($argv[1], $types))));

/* Close file */
fclose($fp);

exit();

我在 Synology DS1513+ 上运行此程序,它总是吐出名称为 @eaDir 的目录。这是我禁用的索引过程,但会在下一次更新时恢复(有时在重新启动后)。 我想添加更多文件类型,而不必担心脚本会检查我上面提到的目录。

我怎样才能做到这一点?

编辑: 经过更多的阅读和研究,我添加了一个嵌套的 if 条件来过滤掉目录,这是包含更改的代码:

#!/usr/bin/php
<?php

/* Run with: php [filename].php /path/to/folder/
  Outputs file_list.json in target folder */

// Where are we running on?
if (PHP_SAPI === 'cli') {
    $argument1 = $argv[1];
    $argument2 = $argv[2];
} else {
    $argument1 = $_GET['argument1'];
    $argument2 = $_GET['argument2'];
}

// Set output dir and file
$out = $argument1 . '/file_list.json';

/*
 * @param Array $types
 * @abstract Array of allowed file types
 */
$types = ['mp3', 'ogg', 'jpg'];
$ignoreDir = ['@eaDir'];

if (!isset($argv[1])) {
    exit("Must specify a directory to scan\n");
}

if (!is_dir($argv[1])) {
    exit($argv[1] . "' is not a directory\n");
}

/*
 * @name getList
 * @param Array $dir
 * @param Array $types
 * @param Array $ignoreDir
 * @abstract Recursively iterates over specified directory
 *           populating array based on array of file extensions
 *           while ignoring directories specified in ignoreDir
 * @return Array $files
 */

function getList($dir, $types, $ignoreDir) {
    $it = new RecursiveDirectoryIterator($dir);
    foreach (new RecursiveIteratorIterator($it) as $file) {
        if (in_array(strtolower(array_pop(explode('.', $file))), $types)) {
            if (!in_array($it, $ignoreDir)) {
                $files[] = $file->__toString();
            }
        }
    }
    return $files;
}

/*
 * @name getDetails
 * @param Array $dir
 * @param Array $types
 * @abstract Recursively iterates over specified directory
 *           populating array with details of each file
 * @return Array $files
 */

function getDetails($types, $array) {
    foreach ($types as $type) {
        foreach ($array as $file) {
            if (strcasecmp($type, array_pop(explode('.', $file))) == 0) {
                $files[$type][basename($file)]['name'] = basename($file);
                $files[$type][basename($file)]['size'] = filesize($file);
                $files[$type][basename($file)]['source'] = $file;
                $files[$type][basename($file)]['date'] = date ("F d Y H:i:s", filemtime($file));
            }
        }
    }
    return array('files' => $files);
}

if (!function_exists('json_encode')) {

    /*
     * @name json_encode
     * @param Mixed $val
     * @abstract Alternate emulated json_encode function
     * @return Object $res
     */
    function json_encode($val)
    {
        if (is_string($val)) return '"'.addslashes($val).'"';
        if (is_numeric($val)) return $val;
        if ($val === null) return 'null';
        if ($val === true) return 'true';
        if ($val === false) return 'false';

        $assoc = false;
        $i = 0;
        foreach ($val as $k=>$v){
            if ($k !== $i++){
                $assoc = true;
                break;
            }
        }
        $res = array();
        foreach ($val as $k=>$v){
            $v = json_encode($v);
            if ($assoc){
                $k = '"'.addslashes($k).'"';
                $v = $k.':'.$v;
            }
            $res[] = $v;
        }
        $res = implode(',', $res);
        return ($assoc)? '{'.$res.'}' : '['.$res.']';
    }
}

/* Open file in write mode */
$fp = fopen($out, 'w');

/* Run application & save file */
fwrite($fp, json_encode(getDetails($types, getList($argv[1], $types, $ignoreDir)), JSON_PRETTY_PRINT));

/* Close file */
fclose($fp);

exit();

我仍然有兴趣了解有关 RecursiveDirectoryIterator 如何使用过滤器的更多信息,但到目前为止,这可以满足我的需求。

【问题讨论】:

    标签: php android json


    【解决方案1】:

    PHP 有一个类似的类,称为 RecursiveCallbackFilterIterator

    http://php.net/manual/en/class.recursivecallbackfilteriterator.php

    如果您使用它而不是当前的递归迭代器,它将让您在遍历每个文件/目录之前“预过滤”。

    您可以根据需要进行过滤,包括目录、文件名、文件大小等。

    然后您可以像这样排除目录:

    $dir = new RecursiveDirectoryIterator('dirYouWantToIterateOver');
    
    //define the directories you don't want to include
    $excludeDirs = array('@eaDir', 'notThisDir', 'notInThisOtherDir');
    
    $files = new RecursiveCallbackFilterIterator($dir, function($file, $key, $iterator) use ($excludeDirs){
        if($iterator->hasChildren() && !in_array($file->getFilename(), $excludeDirs)){
            return true;
        }
        return $file->isFile();
    });
    
    foreach(new RecursiveIteratorIterator($files) as $file){
      //do something with each file
      echo($file->getPathname() . PHP_EOL);
    }
    

    【讨论】:

    • 感谢您让我了解这个类 - 我正在使用 NetBeans 尝试将它实现到我之前发布的代码中,但我遇到了一些障碍 - 我可以做一些非常好的 C 和Java,但 php 需要成为我学习的下一门语言——所以我被困住了。有关如何将其添加到上面提供的源的任何示例?
    • 是否可以使用此解决方案精确定位正确的文件夹。例如。过滤“domain.com/this_folder”而不是“domain.com/subfolder/this_folder”?如果我使用 $excludeDirs = array('this_folder'),它会过滤两者,如果我使用 $excludeDirs = array('subfolder/this_folder'),它不会过滤任何文件夹
    • @Andri 我不直接知道,但您可以扩展此概念以检查“更深”的文件夹方案。有时间我会看看是否可以为这种情况添加一个示例。
    【解决方案2】:

    几天后,我稍微修改了一下,最终解决了这个问题。 如原帖所述,目标是从 recursiveDirectoryIterator 的结果中过滤掉目录,但我的脚本即使在那时也不完整。

    不过,我想分享我完成的脚本。我最后使用了 getID3,你会注意到:

    #!/usr/bin/php
    <?php
    
    /* Run with: php [filename].php /path/to/folder/ /target/folder/
      Outputs $outFileName in target folder */
    setlocale(LC_ALL, 'en_US.UTF-8');
    require_once('/volume1/auto/getID3/getid3/getid3.php');
    
    // Set output filename
    $outFileName = 'file_list_id3.json';
    $scanDir = $argv[1];
    
    /*
     * @param Array $types
     * @abstract Array of allowed file types
     */
    $types = ['mp3'];
    $ignoreDir = ['@eaDir'];
    
    /*
     * @name getList
     * @param Array $dir
     * @param Array $types
     * @param Array $ignoreDir
     * @abstract Recursively iterates over specified directory
     *           populating array based on array of file extensions
     *           while ignoring directories specified in ignoreDir
     * @return Array $files
     */
    
    function getList($dir, $types, $ignoreDir) {
        $it = new RecursiveDirectoryIterator($dir);
        foreach (new RecursiveIteratorIterator($it) as $file) {
            if (in_array(strtolower(array_pop(explode('.', $file))), $types)) {
                if (!in_array($it, $ignoreDir)) {
                    $files[] = $file->__toString();
                }
            }
        }
        return $files;
    }
    
    /*
     * @name getDetails
     * @param Array $dir
     * @param Array $types
     * @abstract Recursively iterates over specified directory
     *           populating array with details of each file
     * @return Array $files
     */
    
    function getDetails($types, $array) {
        foreach ($types as $type) {
            $getID3 = new getID3;                                                   // Initialize getID3 engine
            $getID3->encoding = 'UTF-8';
            foreach ($array as $file) {
                if (strcasecmp($type, array_pop(explode('.', $file))) == 0) {
                    $info = $getID3->analyze($file);                                // Analyse each file
                    getid3_lib::CopyTagsToComments($info);                          // Copy tags to comments
                    $title = $info['tags']['id3v2']['title'][0];                    // title from ID3v2
                    $album = $info['tags']['id3v2']['album'][0];                    // album from ID3v2
                    $artist = $info['tags']['id3v2']['artist'][0];                  // artist from ID3v2
                    $genre = $info['comments_html']['genre'][0];                    // genre from best source
                    $year = $info['comments_html']['year'][0];                      // year from best source
                    $source = $info['filename'];                                    // filename only, no path
                    $track = $info['comments_html']['track'][0];                    // attempt to grab a tracknumber
                    $trackInt = $info['comments']['track'][0];                      // attempt to grab a tracknumber [Integer]
                    $bitrate = round($info['audio']['bitrate'] / 1000).' Kbps';     // audio bitrate
                    $size = filesize($file);                                        // get file size
                    $duration = $info['playtime_string'];                           // playtime in minutes:seconds, formatted string
                    $durationLong = $info['playtime_seconds'];                      // playing time of file, in seconds
                    $site = str_replace("mp3", "", $info['filepath']);              // path to file, not including filename nor enclosing folder                                
                    if(isset($album)){                                              // check for album
                        $imageName = $album.'.jpg';                                 // save imagename as albumname.jpg
                    } else {
                        $imageName = str_replace(".mp3",".jpg", basename($file));   // replace [filename].mp3 with [filename].jpg
                    }
                    if(isset($info['comments']['picture']['0']['data'])){           // check for image
                        $image = $info['comments']['picture']['0']['data'];         // grab image
                        if(file_put_contents($site.'img/'.$imageName, $image));     // save image
                    }
                    $details = array(
                        'title' => $title,
                        'album' => $album,
                        'artist' => $artist,
                        'genre' => $genre,
                        'year' => $year,
                        'source' => $source,
                        'image' => $imageName,
                        'track' => $track,
                        'trackInt' => $trackInt,
                        'size' => $size,
                        'bitrate' => $bitrate,
                        'duration' => $duration,
                        'durationLong' => $durationLong,
                        'site' => $site
                    );
                $files[$type][] = $details;
                }
            }
        }
        return array('media' => $files);
    }
    
    /* Set output directory and filename */
    $out = $scanDir .'../json/'. $outFileName;
    $scan = $scanDir . 'mp3/';
    /* Open file in write mode */
    $fp = fopen($out, 'w');
    /* Run application & save file */
    $to_encode = getDetails($types, getList($scan, $types, $ignoreDir));
    fwrite($fp, json_encode($to_encode, JSON_PRETTY_PRINT));
    /* Close file */
    fclose($fp);
    exit();
    

    然后最终结果是一个脚本,它读取目录中的多个 mp3 文件,并输出一个格式正确的 JSON 文件,准备在 Android 等中解析,以及与您的项目一起使用的图像(如果需要) - 所有同时忽略指定的文件和/或目录(我只需要在我的服务器上处理@eaDir)。

    JSON 文件保存在 json 文件夹中,而图像保存在 mp3 文件上一级的 img 文件夹中 - 保持整洁。

    【讨论】:

      猜你喜欢
      • 2023-03-18
      • 1970-01-01
      • 2013-01-02
      • 2013-07-26
      • 2011-05-31
      • 2016-01-16
      • 2011-02-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多