FilesystemIterator, RegexIterator, et FilterIterator

Répondre


Cette question est un moyen d’empêcher des soumissions automatisées de formulaires par des robots.
Smileys
:D :) :( :o :shock: :? 8-) :lol: :x :P :oops: :cry: :evil: :twisted: :roll: :wink: :!: :?: :idea: :arrow: :| :mrgreen: =D> #-o =P~ :^o :non: :priere: 8-|
Voir plus de smileys
  Revue du sujet
 

  Étendre la vue Revue du sujet : FilesystemIterator, RegexIterator, et FilterIterator

Re: FilesystemIterator, RegexIterator, et FilterIterator

par stealth35 » 19 juil. 2011, 10:38

t'as essayé avec un GlobIterator ?

Re: FilesystemIterator, RegexIterator, et FilterIterator

par AB » 19 juil. 2011, 01:04

RegexIterator est il très bénifique lors de l'utilisation d'expression régulière ou c'est que dans certains cas particuliers ? Merci d'avance :wink:
RegexIterator c'est prévu pour des expressions régulières. C'est souvent plus performant que de mettre un preg_match directement dans la boucle de l'objet à itérer mais c'est le même principe.
J'ai d'ailleurs laissé une batterie de test ici pour que chacun puisse se faire rapidement une idée. Il suffit de changer les deux première variables suivant ses besoins (dans cet exemple je liste les fichiers commençant par la lettre "j" dans le répertoire "PHOTOS").

Re: FilesystemIterator, RegexIterator, et FilterIterator

par Skw33d » 19 juil. 2011, 00:43

RegexIterator est il très bénifique lors de l'utilisation d'expression régulière ou c'est que dans certains cas particuliers ? Merci d'avance :wink:

Re: FilesystemIterator, RegexIterator, et FilterIterator

par AB » 19 juil. 2011, 00:13

Bonjour,

Bon finalement la solution que j'ai retenue pour trouver les index est d'utiliser DirectoryIterator ce qui me permet par ailleurs de pourvoir utiliser conjointement RegexIterator :D
$f = new DirectoryIterator($dossier);

$f = new RegexIterator($f,$matche);

foreach ($f as $value) echo $value->key().' - '.$value->getFilename().'<br />'; 
En performances c'est aussi rapide (à très peu près) que FilesystemIterator::KEY_AS_FILENAME couplé à RegexIterator::MATCH, RegexIterator::USE_KEY

Juste il faut noter que l'index retourné prend en compte les '.' et '..' des répertoires donc le résultat est augmenté de deux par rapport au visuel du répertoire.

Re: FilesystemIterator, RegexIterator, et FilterIterator

par AB » 18 juil. 2011, 02:17

Si cela peut servir à certains voici la batterie de tests utilisée. Si vous avez des améliorations à suggérer...

$dossier = 'PHOTOS/';

$matche = '#^j#ui';



class Filtre_fin extends FilterIterator {

public $posi = 0;
public $match;
public $test=true;
	
	public function _construct($iterator) {}	
	
	public function accept() 
		{
			
			if (preg_match($this->match,parent::current()->getFilename())) 
				{
					$this->test = false;
					return true;
				}
				
			if ($this->test)  $this->posi++;
		}
}


$time = microtime(true);

$dir = new FilesystemIterator($dossier,FilesystemIterator::KEY_AS_FILENAME);
$f2 = new Filtre_fin($dir);
$f2->match = $matche;


foreach ($f2 as $key => $value) echo $key.'<br />';


$time_end = microtime(true);
$time_tot = $time_end - $time;

echo '<br />';

echo 'index = '.$f2->posi.'<br />';
echo 'match = '.iterator_count($f2).'<br />';

echo '<br />';

echo 'durée FilesystemIterator  + FilterIterator et preg_match : ' . $time_tot.'<br />';

echo '<br />';
echo '<br />';






$time = microtime(true);

$files_s = new FilesystemIterator($dossier,FilesystemIterator::KEY_AS_FILENAME);

$i = 0;
$j = 0;
$m = true;

foreach ($files_s as $key => $value) 
{
	if (preg_match($matche,$key)) {echo $key.'<br />';$m=false;$j++;}
	if ($m) $i++;
}

$time_end = microtime(true);
$time_tot = $time_end - $time;

echo '<br />';

echo 'index = '.$i.'<br />';
echo 'match = '.$j.'<br />';

echo '<br />';


echo 'durée FilesystemIterator et preg_match : ' . $time_tot.'<br />';

echo '<br />';
echo '<br />';







$time = microtime(true);

$files_s = new FilesystemIterator($dossier,FilesystemIterator::KEY_AS_FILENAME);
$r = new RegexIterator($files_s, $matche, RegexIterator::MATCH, RegexIterator::USE_KEY);

foreach ($r as $key => $value)  echo $key.'<br />';

$time_end = microtime(true);
$time_tot = $time_end - $time;

echo '<br />';

echo 'index = introuvable <br />';
echo 'match = '.iterator_count($r).'<br />';

echo '<br />';

echo 'durée exécution FilesystemIterator + RegexIteraor : ' . $time_tot.'<br />';

echo '<br />';
echo '<br />';
A noter que dans tous les cas j'utilise FilesystemIterator::KEY_AS_FILENAME car j'ai remarqué un petit gain de performance du fait d'afficher directement $key plutôt que $value->getFilename().

Re: RegexIterator et FilesystemIterator

par AB » 18 juil. 2011, 01:44

Et oui la clé n'a rien à voir avec la position du curseur, d'ailleurs même si j'emploie les filtres à la place du regexIterator et donc sans utiliser FilesystemIterator::KEY_AS_FILENAME, je me retrouve avec le pathname dans la clé. Je cherche encore désespérément une trace de la position du curseur #-o Et pas certain qu'elle soit quelque part sinon il y aurait certainement une fonction inverse de la fonction seek 8-|

Sinon bah je vais boucler benoitement sur mon FilesystemIterator avec le preg_match dans la boucle. La différence avec l'utilisation de regexIterator est de moins 20 à 30% (moins dans certains cas) mais cela reste encore 60% plus rapide (dans de nombreux cas) que si je met un regex dans un filtre.

Bilan de mes tests, regexIterator est optimisé mais par contre FilterIterator est très moyen.

Cela dit si certains peuvent me dire comment retrouver la position du curseur suite à regexIterator... ce sera bienvenu :)

Re: RegexIterator et FilesystemIterator

par stealth35 » 17 juil. 2011, 19:47

peu être avec :
$t->getInnerIterator()->key();
mais comme la clé est le nom de fichier ...

Re: RegexIterator et FilesystemIterator

par AB » 17 juil. 2011, 12:17

Bonjour,

Assez surprenant, je viens d'utiliser ta méthode (un peu plus performante de 7 à 8 % par rapport à un strpos($it_name,'a')===0) dans un filtre avec cette seule condition, et elle est toujours deux fois plus longue qu'un RegexIterator avec le match équivalent #^a#ui. Comme quoi le RegexIterator semble très optimisé :)

Je voudrais maintenant connaître la position des fichiers (par rapport à mon répertoire) pour les fichiers triés, soit combien le regexIerator a dû passer de fichiers en revue avant de matcher le premier fichier ? Si je fais une recherche avec #^c#ui je voudrais savoir combien de fichiers se trouvent avant le premier qui commence par "c". Je me dis que ce devrait être assez simple ... faut croire que je regarde pas au bon endroit. Y'a une méthode simple pour connaître ça à partir de mon code de base ?
<?php
       
$dossier = 'PHOTOS/';

$matche = '#^a#ui';

$f = new FilesystemIterator($dossier, FilesystemIterator::KEY_AS_FILENAME);
               
$r = new RegexIterator($f, $matche, RegexIterator::MATCH, RegexIterator::USE_KEY);

foreach ($r as $t)
                        {
                                echo $t->getFilename();
                        }
?>

Re: RegexIterator et FilesystemIterator

par AB » 14 juil. 2011, 19:58

Parce que mon exemple de regex est minimaliste et n'est pas représentatif de tout ce que je veux faire. Je veux également pouvoir faire des recherche sur des suites de lettres ou plusieurs suites de groupes de lettres, sans que le fichier commence nécessairement par une lettre désignée etc., j'ai donné cet exemple car c'est dans ce cas que le regex posait problème avec FilesystemIterator.

Sinon attention avec la méthode qui consiste à désigner des lettres à l'aide d'un index dans une chaine de caractères car cela peut poser de gros problèmes avec l'utf-8 dans certains cas. Et plutôt que d'essayer de gérer cette méthode suivant les circonstances, j'aurai tendance à dire qu'il vaut mieux simplement éviter de l'utiliser avec l'utf-8.

Re: RegexIterator et FilesystemIterator

par stealth35 » 13 juil. 2011, 20:44

pour quoi faire avec un regexp un substr suffit, voir meme
$it_name[0] === 'a'

Re: Bug avec RegexIterator et FilesystemIterator

par AB » 12 juil. 2011, 17:58

sinon tu pouvais faire ton propre filtre ou utilise GlobIterator :wink:
A propos de filtre, si l'on doit utiliser un regex, on a quand même intérêt à utiliser RegexIterator préalablement à FilterIterator plutôt que de mettre un preg_match dans le filtre. La vitesse de traitement est très sensiblement améliorée.

Test utilisé pour vérifier la différence de vitesse :
(modifier les variables $dossier et $matche suivant vos besoins)
$dossier = 'PHOTOS/';


class Filtre_result_match extends FilterIterator {
 
    public function accept() {
		
		$it = $this->getInnerIterator();
		$it_name = $it->current()->getFilename();
		$matche = '#^a#ui';
		return (!$it->isDot() && !$it->isDir() && $it_name != '.htaccess' && preg_match($matche,$it_name));	
    }

}


$time = microtime(true);

$f = new FilesystemIterator($dossier);
$result = new Filtre_result_match ($f);

foreach ($result as $value) {
    echo $value->getFilename();
}

$time_end = microtime(true);
$time_tot = $time_end - $time;
echo 'durée exécution FilesystemIterator + FilterIterator + preg_match' . $time_tot.'<br />';


echo '<br />';
echo '<br />';


$matche = '#^a#ui';

class Filtre_result extends FilterIterator {
 
    public function accept() {
		
		$it = $this->getInnerIterator();
		$it_name = $it->current()->getFilename();
		return (!$it->isDot() && !$it->isDir() && $it_name != '.htaccess');	
    }

}


$time = microtime(true);

$f = new FilesystemIterator($dossier,FilesystemIterator::KEY_AS_FILENAME);
$r = new RegexIterator($f, $matche, RegexIterator::MATCH, RegexIterator::USE_KEY);

$result = new Filtre_result ($r);

foreach ($result as $value) {
    echo $value->getFilename();
}

$time_end = microtime(true);
$time_tot = $time_end - $time;
echo 'durée exécution FilesystemIterator + RegexIteraor + FilterIterator ' . $time_tot.'<br />';

Re: Bug avec RegexIterator et FilesystemIterator

par stealth35 » 11 juil. 2011, 23:00

sinon tu pouvais faire ton propre filtre ou utilise GlobIterator :wink:

Re: Bug avec RegexIterator et FilesystemIterator

par AB » 11 juil. 2011, 22:42

epommate2 m'avait mis sur la voie, mais j'avais pas su exploiter.

T'as bien fait d'insister :)

En fait il fallait déclarer le mode du RegexIterator avant le flag USE_KEY. Je pensais qu'il devait y avoir une valeur par défaut et ce qui ne m'a pas aidé c'est que cela ne renvoyait pas de message d'erreur, car effectivement la valeur du flag RegexIterator::USE_KEY (=1) à une correspondance dans le mode RegexIterator::GET_MATCH (=1) #-o

Bon donc le code complet avec RegexIterator et FilesystemIterator:
<?php
	
$dossier = 'PHOTOS/';

$matche = '#^a#ui';

$f = new FilesystemIterator($dossier, FilesystemIterator::KEY_AS_FILENAME);
		
$r = new RegexIterator($f, $matche, RegexIterator::MATCH, RegexIterator::USE_KEY);
// équivalent $r = new RegexIterator($f, $matche, 0, 1);

foreach ($r as $t) 
			{
				echo $t->getFilename();
			}
?>

Re: Bug avec RegexIterator et FilesystemIterator

par stealth35 » 11 juil. 2011, 21:10

FilesystemIterator retourne le path pas le nom du fichier

utilise RegexIterator::USE_KEY et FilesystemIterator::KEY_AS_FILENAME

Re: Bug avec RegexIterator et FilesystemIterator

par AB » 11 juil. 2011, 20:46

Salut,

Pas d'autres idées ?