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(), η οποία αναζητά και τα δύο. Αυτές οι μέθοδοι είναι στατικές, οπότε μπορούν να κληθούν χωρίς να δημιουργηθεί μια περίπτωση. Η παράμετρος mask είναι προαιρετική, αν δεν την καθορίσετε, αναζητούνται τα πάντα.

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

Μπορείτε να χρησιμοποιήσετε μπαλαντέρ *, **, ? and [...] στη μάσκα. Μπορείτε ακόμη και να καθορίσετε σε καταλόγους, για παράδειγμα, το 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');

Wildcards wildcards *, **, ? can be used in the path. For example, you can use the path src/*/*.php για την αναζήτηση όλων των αρχείων PHP στους καταλόγους δεύτερου επιπέδου στον κατάλογο src. Ο χαρακτήρας **, που ονομάζεται globstar, είναι ένα ισχυρό ατού γιατί σας επιτρέπει να αναζητήσετε και υποκαταλόγους: χρησιμοποιήστε το src/**/tests/*.php για να αναζητήσετε όλα τα αρχεία PHP στον κατάλογο tests που βρίσκονται στον κατάλογο src ή σε οποιονδήποτε από τους υποκαταλόγους του.

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

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

Άγριοι χαρακτήρες

Μπορείτε να χρησιμοποιήσετε διάφορους ειδικούς χαρακτήρες στη μάσκα:

  • * – replaces any number of arbitrary characters (except /)
  • ** – αντικαθιστά οποιονδήποτε αριθμό αυθαίρετων χαρακτήρων, συμπεριλαμβανομένου του / (δηλ. μπορεί να γίνει αναζήτηση σε πολλαπλά επίπεδα)
  • ? – replaces one arbitrary character (except /)
  • [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 bytes:

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($file->getBasename() !== 'temp');

Ταξινόμηση

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

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

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

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

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

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

($finder = new Finder) // αποθηκεύστε το πρώτο Finder στη μεταβλητή $finder!
	->files('*.php')   // αναζήτηση για αρχεία *.php στο src/
	->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 υλοποιεί τη διεπαφή IteratorAggregate, οπότε μπορείτε να χρησιμοποιήσετε το foreach για να περιηγηθείτε στα αποτελέσματα. Είναι προγραμματισμένο έτσι ώστε τα αποτελέσματα να φορτώνονται μόνο κατά την περιήγησή σας, οπότε αν έχετε μεγάλο αριθμό αρχείων, δεν περιμένει να διαβαστούν όλα.

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

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