Finder: αναζήτηση αρχείων

Χρειάζεστε να βρείτε αρχεία που ταιριάζουν σε ένα συγκεκριμένο μοτίβο; Ο Finder θα σας βοηθήσει με αυτό. Είναι ένα ευέλικτο και γρήγορο εργαλείο για την περιήγηση στη δομή καταλόγων.

Εγκατάσταση:

composer require nette/utils

Τα παρακάτω παραδείγματα προϋποθέτουν τη δημιουργία ενός ψευδωνύμου:

use Nette\Utils\Finder;

Χρήση

Αρχικά, θα δείξουμε πώς μπορείτε να χρησιμοποιήσετε την Nette\Utils\Finder για να εμφανίσετε τα ονόματα των αρχείων με τις επεκτάσεις .txt και .md στον τρέχοντα κατάλογο:

foreach (Finder::findFiles(['*.txt', '*.md']) as $name => $file) {
	echo $file;
}

Ο προεπιλεγμένος κατάλογος αναζήτησης είναι ο τρέχων κατάλογος, αλλά μπορείτε να τον αλλάξετε χρησιμοποιώντας τις μεθόδους in() ή from(). Η μεταβλητή $file είναι ένα στιγμιότυπο της κλάσης FileInfo με πολλές χρήσιμες μεθόδους. Το κλειδί $name περιέχει τη διαδρομή προς το αρχείο ως συμβολοσειρά.

Τι να αναζητήσετε;

Εκτός από τη μέθοδο findFiles(), υπάρχει επίσης η findDirectories(), η οποία αναζητά μόνο καταλόγους, και η find(), η οποία αναζητά και τα δύο. Αυτές οι μέθοδοι είναι στατικές, οπότε μπορούν να κληθούν χωρίς τη δημιουργία στιγμιότυπου. Η παράμετρος με το μοτίβο είναι προαιρετική· αν δεν την καθορίσετε, θα αναζητηθούν τα πάντα.

foreach (Finder::find() as $file) {
	echo $file; // τώρα θα εκτυπωθούν όλα τα αρχεία και οι κατάλογοι
}

Με τις μεθόδους files() και directories() μπορείτε να προσθέσετε τι άλλο να αναζητήσετε. Οι μέθοδοι μπορούν να κληθούν επανειλημμένα, και ως παράμετρος μπορεί να δοθεί και ένας πίνακας μοτίβων:

Finder::findDirectories('vendor') // όλοι οι κατάλογοι
	->files(['*.php', '*.phpt']); // συν όλα τα αρχεία PHP

Μια εναλλακτική στις στατικές μεθόδους είναι η δημιουργία ενός στιγμιότυπου με new Finder (ένα τέτοιο νεοδημιουργημένο αντικείμενο δεν αναζητά τίποτα) και ο καθορισμός του τι να αναζητήσετε χρησιμοποιώντας τις files() και directories():

(new Finder)
	->directories()      // όλοι οι κατάλογοι
	->files('*.php');    // συν όλα τα αρχεία PHP

Στο μοτίβο μπορείτε να χρησιμοποιήσετε χαρακτήρες μπαλαντέρ *, **, ? και [...]. Μπορείτε ακόμη να καθορίσετε και καταλόγους, για παράδειγμα, το src/*.php αναζητά όλα τα αρχεία PHP στον κατάλογο src.

Οι συμβολικοί σύνδεσμοι θεωρούνται επίσης κατάλογοι ή αρχεία.

Πού να ψάξετε;

Ο προεπιλεγμένος κατάλογος αναζήτησης είναι ο τρέχων κατάλογος. Μπορείτε να τον αλλάξετε χρησιμοποιώντας τις μεθόδους in() και from(). Όπως υποδηλώνουν τα ονόματα των μεθόδων, η in() αναζητά μόνο στον συγκεκριμένο κατάλογο, ενώ η from() αναζητά και στους υποκαταλόγους του (αναδρομικά). Αν θέλετε να αναζητήσετε αναδρομικά στον τρέχοντα κατάλογο, μπορείτε να χρησιμοποιήσετε το from('.').

Αυτές οι μέθοδοι μπορούν να κληθούν πολλές φορές ή να τους περάσετε πολλαπλές διαδρομές ως πίνακα· τα αρχεία θα αναζητηθούν τότε σε όλους τους καταλόγους. Αν κάποιος από τους καταλόγους δεν υπάρχει, θα προκληθεί μια εξαίρεση Nette\UnexpectedValueException.

Finder::findFiles('*.php')
	->in(['src', 'tests']) // αναζητά απευθείας στο src/ και tests/
	->from('vendor');      // αναζητά και στους υποκαταλόγους vendor/

Οι σχετικές διαδρομές είναι σχετικές με τον τρέχοντα κατάλογο. Φυσικά, μπορούν να δοθούν και απόλυτες διαδρομές:

Finder::findFiles('*.php')
	->in('/var/www/html');

Στη διαδρομή είναι δυνατό να χρησιμοποιηθούν χαρακτήρες μπαλαντέρ *, **, ?. Για παράδειγμα, με τη διαδρομή src/*/*.php μπορείτε να αναζητήσετε όλα τα αρχεία PHP σε καταλόγους δεύτερου επιπέδου στον κατάλογο src. Ο χαρακτήρας **, γνωστός ως globstar, είναι ένα ισχυρό εργαλείο, καθώς επιτρέπει την αναζήτηση και σε υποκαταλόγους: με το src/**/tests/*.php αναζητάτε όλα τα αρχεία PHP στον κατάλογο tests που βρίσκεται στο src ή σε οποιονδήποτε υποκατάλογό του.

Αντίθετα, οι χαρακτήρες μπαλαντέρ [...] στη διαδρομή δεν υποστηρίζονται, δηλαδή δεν έχουν ειδική σημασία, για να αποφευχθεί ανεπιθύμητη συμπεριφορά σε περίπτωση που ψάχνετε, για παράδειγμα, in(__DIR__) και τυχαία στη διαδρομή υπάρχουν οι χαρακτήρες [].

Κατά την αναζήτηση αρχείων και καταλόγων σε βάθος, επιστρέφεται πρώτα ο γονικός κατάλογος και μετά τα αρχεία που περιέχονται σε αυτόν, κάτι που μπορεί να αντιστραφεί χρησιμοποιώντας το childFirst().

Χαρακτήρες Μπαλαντέρ

Στο μοτίβο μπορείτε να χρησιμοποιήσετε αρκετούς ειδικούς χαρακτήρες:

  • * – αντικαθιστά οποιονδήποτε αριθμό οποιωνδήποτε χαρακτήρων (εκτός από /)
  • ** – αντικαθιστά οποιονδήποτε αριθμό οποιωνδήποτε χαρακτήρων συμπεριλαμβανομένου του / (δηλαδή, μπορεί να γίνει αναζήτηση σε πολλαπλά επίπεδα)
  • ? – αντικαθιστά έναν οποιονδήποτε χαρακτήρα (εκτός από /)
  • [a-z] – αντικαθιστά έναν χαρακτήρα από τη λίστα χαρακτήρων στις αγκύλες
  • [!a-z] – αντικαθιστά έναν χαρακτήρα εκτός της λίστας χαρακτήρων στις αγκύλες

Παραδείγματα χρήσης:

  • img/?.png – αρχεία με μονογράμματο όνομα 0.png, 1.png, x.png, κ.λπ.
  • logs/[0-9][0-9][0-9][0-9]-[01][0-9]-[0-3][0-9].log – αρχεία καταγραφής σε μορφή YYYY-MM-DD
  • src/**/tests/* – αρχεία στους καταλόγους src/tests, src/foo/tests, src/foo/bar/tests και ούτω καθεξής.
  • docs/**.md – όλα τα αρχεία με την επέκταση .md σε όλους τους υποκαταλόγους του καταλόγου docs

Εξαίρεση

Με τη μέθοδο exclude() μπορείτε να εξαιρέσετε αρχεία και καταλόγους από την αναζήτηση. Καθορίζετε το μοτίβο με το οποίο το αρχείο δεν πρέπει να ταιριάζει. Παράδειγμα αναζήτησης αρχείων *.txt εκτός από αυτά που περιέχουν το γράμμα X στο όνομα:

Finder::findFiles('*.txt')
	->exclude('*X*');

Για να παραλείψετε τους διασχιζόμενους υποκαταλόγους, χρησιμοποιήστε το exclude():

Finder::findFiles('*.php')
	->from($dir)
	->exclude('temp', '.git')

Φιλτράρισμα

Ο Finder προσφέρει διάφορες μεθόδους για το φιλτράρισμα των αποτελεσμάτων (δηλαδή, τη μείωσή τους). Μπορείτε να τις συνδυάσετε και να τις καλέσετε επανειλημμένα.

Χρησιμοποιώντας το size(), φιλτράρουμε με βάση το μέγεθος του αρχείου. Έτσι βρίσκουμε αρχεία με μέγεθος μεταξύ 100 και 200 byte:

Finder::findFiles('*.php')
	->size('>=', 100)
	->size('<=', 200);

Η μέθοδος date() φιλτράρει με βάση την ημερομηνία τελευταίας τροποποίησης του αρχείου. Οι τιμές μπορεί να είναι απόλυτες ή σχετικές με την τρέχουσα ημερομηνία και ώρα. Για παράδειγμα, έτσι βρίσκουμε αρχεία που τροποποιήθηκαν τις τελευταίες δύο εβδομάδες:

Finder::findFiles('*.php')
	->date('>', '-2 weeks')
	->from($dir)

Και οι δύο συναρτήσεις κατανοούν τους τελεστές >, >=, <, <=, =, !=, <>.

Ο Finder επιτρέπει επίσης το φιλτράρισμα των αποτελεσμάτων με προσαρμοσμένες συναρτήσεις. Η συνάρτηση λαμβάνει ως παράμετρο ένα αντικείμενο Nette\Utils\FileInfo και πρέπει να επιστρέψει true για να συμπεριληφθεί το αρχείο στα αποτελέσματα.

Παράδειγμα: αναζήτηση αρχείων PHP που περιέχουν τη συμβολοσειρά Nette (ανεξαρτήτως πεζών-κεφαλαίων):

Finder::findFiles('*.php')
	->filter(fn($file) => strcasecmp($file->read(), 'Nette') === 0);

Φιλτράρισμα σε βάθος

Κατά την αναδρομική αναζήτηση, μπορείτε να ορίσετε το μέγιστο βάθος περιήγησης χρησιμοποιώντας τη μέθοδο limitDepth(). Αν ορίσετε limitDepth(1), περιηγούνται μόνο οι πρώτοι υποκατάλογοι, το limitDepth(0) απενεργοποιεί την περιήγηση σε βάθος, και η τιμή –1 ακυρώνει το όριο.

Ο Finder επιτρέπει, χρησιμοποιώντας προσαρμοσμένες συναρτήσεις, να αποφασίσετε σε ποιον κατάλογο θα εισέλθετε κατά την περιήγηση. Η συνάρτηση λαμβάνει ως παράμετρο ένα αντικείμενο Nette\Utils\FileInfo και πρέπει να επιστρέψει true για να εισέλθετε στον κατάλογο:

Finder::findFiles('*.php')
	->descentFilter(fn($file) => $file->getBasename() !== 'temp');

Ταξινόμηση

Ο Finder προσφέρει επίσης αρκετές συναρτήσεις για την ταξινόμηση των αποτελεσμάτων.

Η μέθοδος sortByName() ταξινομεί τα αποτελέσματα με βάση τα ονόματα των αρχείων. Η ταξινόμηση είναι φυσική, δηλαδή χειρίζεται σωστά τους αριθμούς στα ονόματα και επιστρέφει, για παράδειγμα, το foo1.txt πριν από το foo10.txt.

Ο Finder επιτρέπει επίσης την ταξινόμηση με προσαρμοσμένη συνάρτηση. Αυτή λαμβάνει ως παράμετρο δύο αντικείμενα Nette\Utils\FileInfo και πρέπει να επιστρέψει το αποτέλεσμα της σύγκρισης με τον τελεστή <=>, δηλαδή -1, 0 ή 1. Για παράδειγμα, έτσι ταξινομούμε τα αρχεία κατά μέγεθος:

$finder->sortBy(fn($a, $b) => $a->getSize() <=> $b->getSize());

Πολλαπλές διαφορετικές αναζητήσεις

Αν χρειάζεστε να βρείτε περισσότερα διαφορετικά αρχεία σε διαφορετικές τοποθεσίες ή που πληρούν άλλα κριτήρια, χρησιμοποιήστε τη μέθοδο append(). Επιστρέφει ένα νέο αντικείμενο Finder, οπότε είναι δυνατή η αλυσιδωτή κλήση μεθόδων:

($finder = new Finder) // στη μεταβλητή $finder αποθηκεύουμε τον πρώτο Finder!
	->files('*.php')   // στο src/ αναζητούμε αρχεία *.php
	->from('src')
	->append()
	->files('*.md')    // στο docs/ αναζητούμε αρχεία *.md
	->from('docs')
	->append()
	->files('*.json'); // στον τρέχοντα φάκελο αναζητούμε αρχεία *.json

Εναλλακτικά, μπορείτε να χρησιμοποιήσετε τη μέθοδο append() για να προσθέσετε ένα συγκεκριμένο αρχείο (ή έναν πίνακα αρχείων). Τότε επιστρέφει το ίδιο αντικείμενο Finder:

$finder = Finder::findFiles('*.txt')
	->append(__FILE__);

FileInfo

Η Nette\Utils\FileInfo είναι μια κλάση που αντιπροσωπεύει ένα αρχείο ή κατάλογο στα αποτελέσματα αναζήτησης. Είναι μια επέκταση της κλάσης SplFileInfo, η οποία παρέχει πληροφορίες όπως το μέγεθος του αρχείου, η ημερομηνία τελευταίας τροποποίησης, το όνομα, η διαδρομή, κ.λπ.

Επιπλέον, παρέχει μεθόδους για την επιστροφή της σχετικής διαδρομής, που είναι χρήσιμο κατά την περιήγηση σε βάθος:

foreach (Finder::findFiles('*.jpg')->from('.') as $file) {
	$absoluteFilePath = $file->getRealPath();
	$relativeFilePath = $file->getRelativePathname();
}

Επιπλέον, έχετε διαθέσιμες μεθόδους για την ανάγνωση και την εγγραφή του περιεχομένου του αρχείου:

foreach ($finder as $file) {
    $contents = $file->read();
    // ...
    $file->write($contents);
}

Επιστροφή αποτελεσμάτων ως πίνακας

Όπως φάνηκε στα παραδείγματα, ο Finder υλοποιεί το interface IteratorAggregate, οπότε μπορείτε να χρησιμοποιήσετε το foreach για να διασχίσετε τα αποτελέσματα. Είναι προγραμματισμένος έτσι ώστε τα αποτελέσματα να φορτώνονται μόνο κατά τη διάρκεια της διάσχισης, οπότε αν έχετε μεγάλο αριθμό αρχείων, δεν περιμένει μέχρι να διαβαστούν όλα.

Μπορείτε επίσης να λάβετε τα αποτελέσματα ως πίνακα αντικειμένων Nette\Utils\FileInfo, χρησιμοποιώντας τη μέθοδο collect(). Ο πίνακας δεν είναι συσχετιστικός, αλλά αριθμητικός.

$array = $finder->findFiles('*.php')->collect();
έκδοση: 4.0