Je viens de découvrir que mon script me donne une erreur fatale:
Fatal error: Allowed memory size of 268435456 bytes exhausted (tried to allocate 440 bytes) in C:\process_txt.php on line 109
Cette ligne est la suivante:
$lines = count(file($path)) - 1;
Je pense donc qu'il a du mal à charger le fichier dans la mémoire et à compter le nombre de lignes, y a-t-il un moyen plus efficace de le faire sans avoir de problèmes de mémoire?
Les fichiers texte dont j'ai besoin pour compter le nombre de lignes vont de 2 Mo à 500 Mo. Peut-être un concert parfois.
Merci à tous pour toute aide.
\n
) en cours d'analyse sur une machine Windows (PHP_EOL == '\r\n'
)fgets($handle, 1);
?substr_count()
, mais si vous avez de très longues lignes, vous devez appelerwhile()
etfgets()
bien plus encore causant un désavantage. N'oubliez pas:fgets()
ne lit pas ligne par ligne. Il ne lit que le nombre de caractères que vous avez définis$length
et s'il contient un saut de ligne, il arrête tout ce qui$length
a été défini.while(!feof())
vous obligera à lire une ligne supplémentaire, car l'indicateur EOF n'est défini qu'après avoir essayé de lire à la fin du fichier.$line = fgets($handle);
pourrait être simplementfgets($handle);
parce qu'il$line
n'est jamais utilisé.Utiliser une boucle d'
fgets()
appels est la bonne solution et la plus simple à écrire, cependant:même si le fichier est lu en interne à l'aide d'un tampon de 8192 octets, votre code doit toujours appeler cette fonction pour chaque ligne.
il est techniquement possible qu'une seule ligne soit plus grande que la mémoire disponible si vous lisez un fichier binaire.
Ce code lit un fichier par blocs de 8 Ko chacun, puis compte le nombre de sauts de ligne dans ce bloc.
function getLines($file) { $f = fopen($file, 'rb'); $lines = 0; while (!feof($f)) { $lines += substr_count(fread($f, 8192), "\n"); } fclose($f); return $lines; }
Si la longueur moyenne de chaque ligne est au maximum de 4 Ko, vous commencerez déjà à économiser sur les appels de fonction, et ceux-ci peuvent s'additionner lorsque vous traitez de gros fichiers.
Référence
J'ai effectué un test avec un fichier de 1 Go; Voici les résultats:
Le temps est mesuré en secondes en temps réel, voyez ici ce que signifie réel
la source
Solution d'objet orienté simple
$file = new \SplFileObject('file.extension'); while($file->valid()) $file->fgets(); var_dump($file->key());
Mise à jour
Une autre façon de faire est avec
PHP_INT_MAX
enSplFileObject::seek
méthode.$file = new \SplFileObject('file.extension', 'r'); $file->seek(PHP_INT_MAX); echo $file->key() + 1;
la source
wc -l
(à cause de la fourche je suppose), surtout sur les petits fichiers.Si vous l'exécutez sur un hôte Linux / Unix, la solution la plus simple serait d'utiliser
exec()
ou similaire pour exécuter la commandewc -l $path
. Assurez-vous simplement que vous avez nettoyé d'$path
abord pour être sûr que ce n'est pas quelque chose comme "/ chemin / vers / fichier; rm -rf /".la source
Il existe un moyen plus rapide que j'ai trouvé qui ne nécessite pas de boucle sur tout le fichier
uniquement sur les systèmes * nix , il pourrait y avoir une manière similaire sur Windows ...
$file = '/path/to/your.file'; //Get number of lines $totalLines = intval(exec("wc -l '$file'"));
la source
exec('wc -l '.escapeshellarg($file).' 2>/dev/null')
Si vous utilisez PHP 5.5, vous pouvez utiliser un générateur . Cela ne fonctionnera dans aucune version de PHP avant la version 5.5. Depuis php.net:
"Les générateurs fournissent un moyen simple d'implémenter des itérateurs simples sans la surcharge ou la complexité de l'implémentation d'une classe qui implémente l'interface Iterator."
// This function implements a generator to load individual lines of a large file function getLines($file) { $f = fopen($file, 'r'); // read each line of the file without loading the whole file to memory while ($line = fgets($f)) { yield $line; } } // Since generators implement simple iterators, I can quickly count the number // of lines using the iterator_count() function. $file = '/path/to/file.txt'; $lineCount = iterator_count(getLines($file)); // the number of lines in the file
la source
try
/finally
n'est pas strictement nécessaire, PHP fermera automatiquement le fichier pour vous. Vous devriez probablement également mentionner que le comptage réel peut être fait en utilisantiterator_count(getFiles($file))
:)Ceci est un complément à la solution de Wallace de Souza
Il saute également les lignes vides lors du comptage:
function getLines($file) { $file = new \SplFileObject($file, 'r'); $file->setFlags(SplFileObject::READ_AHEAD | SplFileObject::SKIP_EMPTY | SplFileObject::DROP_NEW_LINE); $file->seek(PHP_INT_MAX); return $file->key() + 1; }
la source
Si vous êtes sous Linux, vous pouvez simplement faire:
number_of_lines = intval(trim(shell_exec("wc -l ".$file_name." | awk '{print $1}'")));
Il vous suffit de trouver la bonne commande si vous utilisez un autre OS
Cordialement
la source
private static function lineCount($file) { $linecount = 0; $handle = fopen($file, "r"); while(!feof($handle)){ if (fgets($handle) !== false) { $linecount++; } } fclose($handle); return $linecount; }
Je voulais ajouter un petit correctif à la fonction ci-dessus ...
dans un exemple spécifique où j'avais un fichier contenant le mot «test», la fonction a renvoyé 2 comme résultat. donc j'avais besoin d'ajouter une vérification si fgets retournait faux ou non :)
s'amuser :)
la source
Basé sur la solution de dominic Rodger, voici ce que j'utilise (il utilise wc si disponible, sinon des replis vers la solution de dominic Rodger).
class FileTool { public static function getNbLines($file) { $linecount = 0; $m = exec('which wc'); if ('' !== $m) { $cmd = 'wc -l < "' . str_replace('"', '\\"', $file) . '"'; $n = exec($cmd); return (int)$n + 1; } $handle = fopen($file, "r"); while (!feof($handle)) { $line = fgets($handle); $linecount++; } fclose($handle); return $linecount; } }
https://github.com/lingtalfi/Bat/blob/master/FileTool.php
la source
Le comptage du nombre de lignes peut se faire à l'aide des codes suivants:
<?php $fp= fopen("myfile.txt", "r"); $count=0; while($line = fgetss($fp)) // fgetss() is used to get a line from a file ignoring html tags $count++; echo "Total number of lines are ".$count; fclose($fp); ?>
la source
Vous avez plusieurs options. La première consiste à augmenter la mémoire disponible autorisée, ce qui n'est probablement pas la meilleure façon de faire les choses étant donné que vous déclarez que le fichier peut devenir très volumineux. L'autre façon consiste à utiliser fgets pour lire le fichier ligne par ligne et incrémenter un compteur, ce qui ne devrait causer aucun problème de mémoire car seule la ligne actuelle est en mémoire à la fois.
la source
Il y a une autre réponse qui, à mon avis, pourrait être un bon ajout à cette liste.
Si vous avez
perl
installé et pouvez exécuter des choses à partir du shell en PHP:$lines = exec('perl -pe \'s/\r\n|\n|\r/\n/g\' ' . escapeshellarg('largetextfile.txt') . ' | wc -l');
Cela devrait gérer la plupart des sauts de ligne que ce soit à partir de fichiers Unix ou Windows créés.
DEUX inconvénients (au moins):
1) Ce n'est pas une bonne idée d'avoir votre script tellement dépendant du système sur lequel il s'exécute (il n'est peut-être pas prudent de supposer que Perl et wc sont disponibles)
2) Juste une petite erreur en vous échappant et vous avez remis l'accès à un shell sur votre machine.
Comme pour la plupart des choses que je sais (ou pense savoir) sur le codage, j'ai obtenu cette information ailleurs:
Article de John Reeve
la source
public function quickAndDirtyLineCounter() { echo "<table>"; $folders = ['C:\wamp\www\qa\abcfolder\', ]; foreach ($folders as $folder) { $files = scandir($folder); foreach ($files as $file) { if($file == '.' || $file == '..' || !file_exists($folder.'\\'.$file)){ continue; } $handle = fopen($folder.'/'.$file, "r"); $linecount = 0; while(!feof($handle)){ if(is_bool($handle)){break;} $line = fgets($handle); $linecount++; } fclose($handle); echo "<tr><td>" . $folder . "</td><td>" . $file . "</td><td>" . $linecount . "</td></tr>"; } } echo "</table>"; }
la source
J'utilise cette méthode pour compter uniquement le nombre de lignes dans un fichier. Quel est l'inconvénient de faire ce versets les autres réponses. Je vois beaucoup de lignes par opposition à ma solution à deux lignes. Je suppose qu'il y a une raison pour laquelle personne ne fait ça.
$lines = count(file('your.file')); echo $lines;
la source
La solution multiplateforme la plus succincte qui ne met en mémoire tampon qu'une seule ligne à la fois.
$file = new \SplFileObject(__FILE__); $file->setFlags($file::READ_AHEAD); $lines = iterator_count($file);
Malheureusement, nous devons définir le
READ_AHEAD
drapeau sinoniterator_count
bloque indéfiniment. Sinon, ce serait un one-liner.la source
Pour ne compter que les lignes, utilisez:
$handle = fopen("file","r"); static $b = 0; while($a = fgets($handle)) { $b++; } echo $b;
la source