如何用PHP遍历文件目录(含子目录)并查找文件被引用情况
Solution: Track File References Across Directory Structure
Great start with your recursive directory traversal! To add the file reference lookup functionality, we'll break this into three key steps: collect all file metadata first (to avoid repeated file reads), build a reference map of which files mention which filenames, then output the directory structure with reference info.
Here's the complete implementation:
<?php // Step 1: Recursively collect all files with their content and relative paths function collectAllFiles($dir, $baseDir = null) { static $files = []; if ($baseDir === null) { $baseDir = $dir; // Store root directory to generate relative paths } $ffs = scandir($dir); foreach ($ffs as $ff) { if ($ff === '.' || $ff === '..') continue; $fullPath = $dir . DIRECTORY_SEPARATOR . $ff; $relativePath = str_replace($baseDir . DIRECTORY_SEPARATOR, '', $fullPath); if (is_dir($fullPath)) { collectAllFiles($fullPath, $baseDir); } else { // Handle cases where file can't be read (e.g., permissions) $content = @file_get_contents($fullPath) ?: ''; $files[$relativePath] = [ 'filename' => basename($fullPath), 'content' => $content ]; } } return $files; } // Step 2: Build a map of which files reference each filename function buildFileReferences($files) { $references = []; foreach ($files as $filePath => $fileInfo) { $targetFilename = $fileInfo['filename']; $foundIn = []; foreach ($files as $otherPath => $otherInfo) { // Skip checking the file against itself if ($filePath === $otherPath) continue; // Check if the target filename exists in the other file's content if (strpos($otherInfo['content'], $targetFilename) !== false) { $foundIn[] = $otherPath; } } $references[$filePath] = $foundIn; } return $references; } // Step 3: Print directory structure with reference annotations function printDirectoryWithReferences($dir, $baseDir, $references, $indent = 0) { $ffs = scandir($dir); // Sort directories first, then files (optional but cleaner) usort($ffs, function($a, $b) use ($dir) { $aIsDir = is_dir($dir . DIRECTORY_SEPARATOR . $a); $bIsDir = is_dir($dir . DIRECTORY_SEPARATOR . $b); if ($aIsDir && !$bIsDir) return -1; if (!$aIsDir && $bIsDir) return 1; return strcmp($a, $b); }); foreach ($ffs as $ff) { if ($ff === '.' || $ff === '..') continue; $fullPath = $dir . DIRECTORY_SEPARATOR . $ff; $relativePath = str_replace($baseDir . DIRECTORY_SEPARATOR, '', $fullPath); // Add indentation for subdirectories echo str_repeat(' ', $indent * 4); echo $ff; if (is_dir($fullPath)) { echo PHP_EOL; printDirectoryWithReferences($fullPath, $baseDir, $references, $indent + 1); } else { $foundIn = $references[$relativePath] ?? []; if (!empty($foundIn)) { echo ' => this filename is exist in ' . implode(', ', $foundIn); } echo PHP_EOL; } } } // Execute the workflow $rootDir = 'C:\Users\vmali\Desktop\Test-Directories'; $allFiles = collectAllFiles($rootDir); $fileReferences = buildFileReferences($allFiles); printDirectoryWithReferences($rootDir, $rootDir, $fileReferences); ?>
Key Details Explained:
Collecting File Metadata:
- We first traverse the entire directory once to store each file's relative path, filename, and content. This avoids reading the same file multiple times (a big efficiency win for large directories).
- The
@file_get_contentssuppresses warnings for unreadable files, and we default to an empty string to keep the script running.
Building Reference Map:
- For each file, we check if its filename appears in the content of every other file. We skip self-references since you don't want to count a file mentioning itself.
- We store results in an array where keys are file paths, and values are lists of paths where the filename was found.
Printing the Structure:
- We recursively traverse the directory again, adding indentation for subdirectories to match your desired output format.
- We look up the reference map for each file and append the "exists in" message if there are matches.
Example Output (Matching Your Request):
MainFolder file1.txt => this filename is exist in file2.txt, SubFolder/file5.txt, SubFolder/SubSubFolder/file9.txt file2.txt => this filename is exist in file1.txt, SubFolder/file5.txt file3.txt => this filename is exist in file1.txt, file2.txt file4.txt SubFolder file5.txt file6.txt file7.txt SubSubFolder file8.txt file9.txt => this filename is exist in (none, based on your sample structure) file10.txt => this filename is exist in SubFolder/SubSubFolder/file9.txt
内容的提问来源于stack exchange,提问作者VBMali
相关产品推荐
相关产品推荐

