Hoe lees je een groot bestand regel voor regel?

Ik wil een bestand regel voor regel lezen, maar zonder het volledig in het geheugen te laden.

Mijn bestand is te groot om in het geheugen te openen, en als ik dit probeer, krijg ik altijd fouten in het geheugen.

De bestandsgrootte is 1 GB.


Antwoord 1, autoriteit 100%

U kunt de functie fgets()gebruiken om het bestand regel voor regel te lezen:

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

Antwoord 2, autoriteit 18%

if ($file = fopen("file.txt", "r")) {
    while(!feof($file)) {
        $line = fgets($file);
        # do same stuff with the $line
    }
    fclose($file);
}

Antwoord 3, autoriteit 14%

U kunt een objectgeoriënteerde interfaceklasse gebruiken voor een bestand – SplFileObjecthttp:/ /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;

Antwoord 4, autoriteit 10%

Als je een groot bestand opent, wil je waarschijnlijk Generators naast fgets() gebruiken om te voorkomen dat het hele bestand in het geheugen wordt geladen:

/**
 * @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);
};

Gebruik het als volgt:

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

Op deze manier kunt u individuele bestandsregels binnen de foreach() verwerken.

Opmerking: Generatoren vereisen >= PHP 5.5


Antwoord 5, autoriteit 5%

Er is een functie file()die een array retourneert van de regels in het bestand.

foreach(file('myfile.txt') as $line) {
   echo $line. "\n";
}

Antwoord 6, autoriteit 4%

Gebruik buffertechnieken om het bestand te lezen.

$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);
    ///
}

Antwoord 7, autoriteit 3%

Het voor de hand liggende antwoord was er niet in alle reacties.
PHP heeft een nette streaming-delimiter-parser beschikbaar die precies voor dat doel is gemaakt.

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

Antwoord 8, autoriteit 3%

foreach (new SplFileObject(__FILE__) as $line) {
    echo $line;
}

Antwoord 9

Dit is hoe ik het doe met zeer grote bestanden (getest met maximaal 100G). En het is sneller dan 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);

Antwoord 10

Wees voorzichtig met de ‘while(!feof … fgets()’-dingen, fgets kan een fout krijgen (returnfing false) en voor altijd herhalen zonder het einde van het bestand te bereiken. codaddict was het dichtst bij correct, maar toen je ‘ terwijl de lus van fgets eindigt, controleer dan feof; zo niet waar, dan had je een fout.


Antwoord 11

Een van de populaire oplossingen voor deze vraag heeft problemen met het nieuwe regelteken. Het kan vrij eenvoudig worden opgelost met een simpele str_replace.

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

Antwoord 12

SplFileObject is handig als het gaat om het omgaan met grote bestanden.

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;
}

Antwoord 13

<?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++;
}
?>

Antwoord 14

Functie om te lezen met array-retour

function read_file($filename = ''){
    $buffer = array();
    $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
    }
    return $buffer;
}

Other episodes