Finder: Dosya Arama

Belirli bir maskeyle eşleşen dosyaları mı bulmanız gerekiyor? Finder size yardımcı olabilir. Dizin yapısına göz atmak için çok yönlü ve hızlı bir araçtır.

Kurulum:

composer require nette/utils

Örneklerde bir takma ad oluşturulduğu varsayılmaktadır:

use Nette\Utils\Finder;

Kullanma

İlk olarak, geçerli dizindeki .txt ve .md uzantılı dosya adlarını listelemek için Nette\Utils\Finder adresini nasıl kullanabileceğinizi görelim:

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

Arama için varsayılan dizin geçerli dizindir, ancak in() veya from() yöntemlerini kullanarak bunu değiştirebilirsiniz. $file değişkeni, birçok yararlı yöntemi olan FileInfo sınıfının bir örneğidir. $name anahtarı, dosyanın yolunu bir dize olarak içerir.

Ne Aranmalı?

findFiles() yöntemine ek olarak, yalnızca dizinleri arayan findDirectories() ve her ikisini de arayan find() yöntemleri de vardır. Bu yöntemler statiktir, yani bir örnek oluşturmadan çağrılabilirler. Maske parametresi isteğe bağlıdır, belirtmezseniz her şey aranır.

foreach (Finder::find() as $file) {
	echo $file; // şimdi tüm dosyalar ve dizinler listeleniyor
}

Başka nelerin aranacağını eklemek için files() ve directories() yöntemlerini kullanın. Yöntemler tekrar tekrar çağrılabilir ve parametre olarak bir dizi maske sağlanabilir:

Finder::findDirectories('vendor') // tüm dizinler
	->files(['*.php', '*.phpt']); // artı tüm PHP dosyaları

Statik yöntemlere bir alternatif de new Finder adresini kullanarak bir örnek oluşturmak (bu şekilde oluşturulan yeni nesne hiçbir şey aramaz) ve files() ve directories() adreslerini kullanarak ne aranacağını belirtmektir:

(new Finder)
	->directories() // tüm dizinler
	->files('*.php'); // artı tüm PHP dosyaları

Joker karakter leri *, ** adresinde kullanabilirsiniz, ? and [...] maske içinde. Dizinleri bile belirtebilirsiniz, örneğin src/*.php, src dizinindeki tüm PHP dosyalarını arayacaktır.

Simbağlar da dizin veya dosya olarak kabul edilir.

Varsayılan arama dizini geçerli dizindir. Bunu in() ve from() yöntemlerini kullanarak değiştirebilirsiniz. Yöntem adlarından da görebileceğiniz gibi, in() yalnızca geçerli dizini ararken, from() alt dizinleri de arar (özyinelemeli olarak). Geçerli dizinde özyinelemeli arama yapmak istiyorsanız, from('.') adresini kullanabilirsiniz.

Bu yöntemler birden çok kez çağrılabilir veya bu yöntemlere birden çok yol diziler olarak aktarılabilir, bu durumda dosyalar tüm dizinlerde aranacaktır. Dizinlerden biri mevcut değilse, bir Nette\UnexpectedValueException atılır.

Finder::findFiles('*.php')
	->in(['src', 'tests']) // doğrudan src/ ve tests/ içinde arama yapar
	->from('vendor');      // vendor/ alt dizinlerinde de arama yapar

Göreceli yollar geçerli dizine görelidir. Elbette mutlak yollar da belirtilebilir:

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

Joker karakterler *, **, ? can be used in the path. For example, you can use the path src/*/*.php src dizinindeki ikinci seviye dizinlerdeki tüm PHP dosyalarını aramak için. Globstar olarak adlandırılan ** karakteri güçlü bir kozdur, çünkü alt dizinleri de aramanıza izin verir: src veya alt dizinlerinden herhangi birinde bulunan tests dizinindeki tüm PHP dosyalarını aramak için src/**/tests/*.php kullanın.

Öte yandan, joker karakterler [...] karakterleri yolda desteklenmez, yani örneğin in(__DIR__) için arama yapmanız ve şans eseri [] karakterlerinin yolda görünmesi durumunda istenmeyen davranışı önlemek için özel bir anlamı yoktur.

Dosya ve dizinleri derinlemesine ararken, önce üst dizin ve ardından içinde bulunan dosyalar döndürülür, bu childFirst() ile tersine çevrilebilir.

Wildcards

Maskede birkaç özel karakter kullanabilirsiniz:

  • * – replaces any number of arbitrary characters (except /)
  • ** – / dahil olmak üzere herhangi bir sayıda rastgele karakterin yerini alır (yani çok seviyeli olarak aranabilir)
  • ? – replaces one arbitrary character (except /)
  • [a-z] – köşeli parantez içindeki karakter listesinden bir karakteri değiştirir
  • [!a-z] – köşeli parantez içindeki karakter listesinin dışındaki bir karakteri değiştirir

Kullanım örnekleri:

  • img/?.png – 0.png, 1.png, x.png, vb. tek harfli adlara sahip dosyalar.
  • logs/[0-9][0-9][0-9][0-9]-[01][0-9]-[0-3][0-9].log – biçimindeki günlük dosyaları YYYY-MM-DD
  • src/**/tests/* – src/tests, src/foo/tests, src/foo/bar/tests ve benzeri dizinlerdeki dosyalar.
  • docs/**.md – dizinin tüm alt dizinlerinde bulunan .md uzantılı tüm dosyalar docs

Hariç

Dosyaları ve dizinleri aramaların dışında tutmak için exclude() yöntemini kullanın. Dosyanın eşleşmemesi gereken bir maske belirtirsiniz. Adında X harfi bulunanlar dışında *.txt dosyalarının aranmasına örnek:

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

Taranan alt dizinleri atlamak için exclude() adresini kullanın:

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

Filtreleme

Finder, sonuçları filtrelemek (yani azaltmak) için çeşitli yöntemler sunar. Bunları birleştirebilir ve tekrar tekrar çağırabilirsiniz.

Dosya boyutuna göre filtrelemek için size() adresini kullanın. Bu şekilde, boyutları 100 ile 200 bayt arasında olan dosyaları buluruz:

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

date() yöntemi, dosyanın en son değiştirildiği tarihe göre filtreler. Değerler, geçerli tarih ve saate göre mutlak veya göreli olabilir; örneğin, son iki hafta içinde değiştirilen dosyalar bu şekilde bulunabilir:

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

Her iki işlev de >, >=, <, <=, =, !=, <> operatörlerini anlar.

Finder ayrıca özel işlevler kullanarak sonuçları filtrelemenize de olanak tanır. İşlev, parametre olarak bir Nette\Utils\FileInfo nesnesi alır ve dosyayı sonuçlara dahil etmek için true döndürmelidir.

Örnek: Nette dizesini içeren PHP dosyalarını arayın (büyük/küçük harfe duyarlı değil):

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

Derinlik Filtreleme

Özyinelemeli arama yaparken, limitDepth() yöntemini kullanarak maksimum tarama derinliğini ayarlayabilirsiniz. limitDepth(1) ayarlarsanız, yalnızca ilk alt dizinler taranır, limitDepth(0) derinlik taramasını devre dışı bırakır ve –1 değeri sınırı iptal eder.

Finder, tarama yaparken hangi dizine girileceğine karar vermek için kendi işlevlerini kullanmanıza izin verir. İşlev parametre olarak bir Nette\Utils\FileInfo nesnesi alır ve dizine girmek için true döndürmelidir:

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

Sıralama

Finder ayrıca sonuçları sıralamak için çeşitli işlevler sunar.

sortByName() yöntemi sonuçları dosya adına göre sıralar. Sıralama doğaldır, yani adlardaki sayıları doğru bir şekilde işler ve örneğin foo1.txt 'u foo10.txt'dan önce döndürür.

Finder ayrıca özel bir fonksiyon kullanarak sıralama yapmanıza da olanak tanır. Parametre olarak iki Nette\Utils\FileInfo nesnesi alır ve operatör ile karşılaştırmanın sonucunu döndürmelidir <=>yani -1, 0 nebo 1. Örneğin, dosyaları boyutlarına göre bu şekilde sıralayabiliriz:

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

Çoklu Farklı Aramalar

Farklı konumlarda veya farklı kriterleri karşılayan birden fazla farklı dosya bulmanız gerekiyorsa, append() yöntemini kullanın. Yöntem çağrılarını zincirleyebilmeniz için yeni bir Finder nesnesi döndürür:

($finder = new Finder) // ilk Finder'ı $finder değişkeninde saklayın!
	->files('*.php') // src/ içinde *.php dosyalarını ara
	->from('src')
	->append()
	->files('*.md') // docs/ içinde *.md dosyalarını arayın
	->from('docs')
	->append()
	->files('*.json'); // geçerli klasörde *.json dosyalarını arayın

Alternatif olarak, belirli bir dosyayı (veya bir dizi dosyayı) eklemek için append() yöntemini kullanabilirsiniz. O zaman aynı nesneyi döndürür Finder:

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

FileInfo

Nette\Utils\FileInfo, arama sonuçlarındaki bir dosya veya dizini temsil eden bir sınıftır. Dosya boyutu, son değiştirilme tarihi, adı, yolu gibi bilgileri sağlayan SplFileInfo sınıfının bir uzantısıdır.

Ayrıca, derinlemesine tarama yaparken yararlı olan göreli yolları döndürmek için yöntemler sağlar:

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

Bir dosyanın içeriğini okumak ve yazmak için de yöntemleriniz vardır:

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

Sonuçları Dizi Olarak Döndürme

Örneklerde görüldüğü gibi, Finder IteratorAggregate arayüzünü uygular, böylece sonuçlara göz atmak için foreach adresini kullanabilirsiniz. Sonuçlar yalnızca siz göz attıkça yüklenecek şekilde programlanmıştır, bu nedenle çok sayıda dosyanız varsa, hepsinin okunmasını beklemez.

Ayrıca collect() yöntemini kullanarak sonuçların Nette\Utils\FileInfo nesnelerinden oluşan bir dizi olarak döndürülmesini sağlayabilirsiniz. Dizi ilişkisel değil, sayısaldır.

$array = $finder->findFiles('*.php')->collect();
versiyon: 4.0