web-dev-qa-db-fra.com

Comment lire un fichier volumineux ligne par ligne?

Je veux lire un fichier ligne par ligne, mais sans le charger complètement en mémoire.

Mon fichier est trop volumineux pour pouvoir être ouvert en mémoire. Si j'essaie de le faire, les erreurs de mémoire sont toujours insuffisantes.

La taille du fichier est de 1 Go.

430
adnan masood

Vous pouvez utiliser la fonction fgets() pour lire le fichier ligne par ligne:

$handle = fopen("inputfile.txt", "r");
if ($handle) {
    while (($line = fgets($handle)) !== false) {
        // process the line read.
    }

    fclose($handle);
} else {
    // error opening the file.
} 
642
codaddict
if ($file = fopen("file.txt", "r")) {
    while(!feof($file)) {
        $line = fgets($file);
        # do same stuff with the $line
    }
    fclose($file);
}
122
Syuaa SE

Vous pouvez utiliser une classe d'interface orientée objet pour un fichier - SplFileObject http://php.net/manual/en/splfileobject.fgets .php (PHP 5> = 5.1.0)

<?php

$file = new SplFileObject("file.txt");

// Loop until we reach the end of the file.
while (!$file->eof()) {
    // Echo one line from the file.
    echo $file->fgets();
}

// Unset the file to call __destruct(), closing the file handle.
$file = null;
79
elshnkhll

Si vous ouvrez un gros fichier, vous voudrez probablement utiliser Generators avec fgets () pour éviter de charger tout le fichier en mémoire:

/**
 * @return Generator
 */
$fileData = function() {
    $file = fopen(__DIR__ . '/file.txt', 'r');

    if (!$file)
        die('file does not exist or cannot be opened');

    while (($line = fgets($file)) !== false) {
        yield $line;
    }

    fclose($file);
};

Utilisez-le comme ceci:

foreach ($fileData() as $line) {
    // $line contains current line
}

De cette façon, vous pouvez traiter des lignes de fichier individuelles dans foreach ().

Remarque: Les générateurs nécessitent> = PHP 5.5

49
Nino Škopac

Utilisez des techniques de mise en mémoire tampon pour lire le fichier.

$filename = "test.txt";
$source_file = fopen( $filename, "r" ) or die("Couldn't open $filename");
while (!feof($source_file)) {
    $buffer = fread($source_file, 4096);  // use a buffer of 4KB
    $buffer = str_replace($old,$new,$buffer);
    ///
}
28
Starx

Il existe une fonction file() qui renvoie un tableau des lignes contenues dans le fichier.

foreach(file('myfile.txt') as $line) {
   echo $line. "\n";
}
27
NoImaginationGuy
foreach (new SplFileObject(__FILE__) as $line) {
    echo $line;
}
15
Quolonel Questions

Soyez prudent avec les éléments "while (! Feof ... fgets ()", fgets peut obtenir une erreur (returnfing false) et boucle en boucle sans atteindre la fin du fichier. Codaddict était proche de l'exactitude, mais lorsque votre "tant que fgets" boucle se termine, vérifiez feof; sinon, vous avez une erreur.

6
Cuse70

La réponse évidente ne figurait pas dans toutes les réponses. PHP dispose d'un analyseur de séparateur de flux en continu parfaitement conçu à cet effet.

$fp=fopen("/path/to/the/file", "r+");
while ($line = stream_get_line($fp, 1024 * 1024, "\n"))
{
echo $line;
}
fclose($fp);
6
John

Une des solutions populaires à cette question aura des problèmes avec le caractère de nouvelle ligne. Il peut être corrigé assez facilement avec un simple str_replace.

$handle = fopen("some_file.txt", "r");
if ($handle) {
    while (($line = fgets($handle)) !== false) {
        $line = str_replace("\n", "", $line);
    }
    fclose($handle);
}
5
Tegan Snyder

C'est comme ça que je gère avec de très gros fichiers (testé avec jusqu'à 100G). Et c'est plus rapide que fgets ()

$block =1024*1024;//1MB or counld be any higher than HDD block_size*2
if ($fh = fopen("file.txt", "r")) { 
    $left='';
    while (!feof($fh)) {// read the file
       $temp = fread($fh, $block);  
       $fgetslines = explode("\n",$temp);
       $fgetslines[0]=$left.$fgetslines[0];
       if(!feof($fh) )$left = array_pop($lines);           
       foreach ($fgetslines as $k => $line) {
           //do smth with $line
        }
     }
}
fclose($fh);
4
Metodi Darzev

SplFileObject est utile pour gérer des fichiers volumineux.

function parse_file($filename)
{
    try {
        $file = new SplFileObject($filename);
    } catch (LogicException $exception) {
        die('SplFileObject : '.$exception->getMessage());
    }
    while ($file->valid()) {
        $line = $file->fgets();
        //do something with $line
    }

    //don't forget to free the file handle.
    $file = null;
}
3
xanadev
<?php
echo '<meta charset="utf-8">';

$k= 1;
$f= 1;
$fp = fopen("texttranslate.txt", "r");
while(!feof($fp)) {
    $contents = '';
    for($i=1;$i<=1500;$i++){
        echo $k.' -- '. fgets($fp) .'<br>';$k++;
        $contents .= fgets($fp);
    }
    echo '<hr>';
    file_put_contents('Split/new_file_'.$f.'.txt', $contents);$f++;
}
?>
0