Manipulation de contenu de fichiers avec pointeur

Présentation

Cette page aborde la manipulation de contenu de fichiers avec un pointeur.

Quand vous ouvrez un fichier avec cette approche, PHP crée un pointeur de fichier. Imaginez un doigt posé sur une page d'un livre. Ce doigt indique l'endroit où vous en êtes dans votre lecture. Quand vous lisez une ligne, le doigt avance automatiquement à la ligne suivante. Quand vous écrivez, le doigt avance après ce que vous venez d'écrire. Vous pouvez aussi déplacer ce doigt librement pour revenir en arrière ou sauter à un endroit précis.

Pour une approche plus simple qui lit ou écrit un fichier en une seule opération, référez-vous au chapitre basé sur file_get_contents() et file_put_contents().

L'approche avec pointeur devient utile dans les situations suivantes :

  • Fichier volumineux : plutôt que de tout charger en mémoire, on lit progressivement, ligne par ligne ou par blocs.
  • Traitement au fil de l'eau : on traite chaque ligne dès sa lecture, sans devoir d'abord tout lire.
  • Ajout de données ou logs : on écrit directement en fin de fichier sans toucher au contenu existant.
  • Contrôle précis : on choisit exactement combien d'octets lire, ou on revient à un endroit précis dans le fichier.
  • Verrouillage sur plusieurs actions : on maintient un verrou pendant toute une séquence d'opérations, pas seulement pendant une seule écriture.

Si vous avez besoin du contenu complet tout de suite et que le fichier est petit ou moyen, l'approche en une opération est souvent suffisante. Si vous devez traiter progressivement, limiter l'usage mémoire ou contrôler le verrouillage, l'approche avec pointeur devient plus adaptée.

Ouvrir et fermer un fichier

La fonction fopen() ouvre un fichier et renvoie une ressource. Cette ressource représente le pointeur qui indique où vous en êtes dans le fichier.
fopen() attend au minimum deux arguments :

  1. le chemin vers le fichier sous forme de chaîne de caractères,
  2. le mode d'ouverture sous forme de chaîne de caractères.

Si l'ouverture échoue (fichier introuvable, droits insuffisants, etc.), fopen() renvoie false. Il est indispensable de vérifier la valeur de retour avant de continuer.

Une fois vos opérations terminées, fermez toujours la ressource avec fclose(). Cela libère le fichier et finalise correctement les écritures éventuelles.
fclose() attend un seule paramètre correspondant à la ressource du fichier déjà ouvert (retournée parfopen()).


                    <?php
                    // Tenter d'ouvrir le fichier en lecture.
                    $monFichier = fopen(__DIR__ . '/mon_fichier.txt', 'r');

                    // Vérifier que l'ouverture a réussi avant de continuer.
                    if ($monFichier === false)
                    {
                        exit('Impossible d\'ouvrir le fichier.');
                    }

                    // À partir d'ici, $monFichier est une ressource valide.
                    // ... opérations sur le fichier ...

                    // Fermer le fichier une fois les opérations terminées.
                    fclose($monFichier);
                

Modes d'ouverture

Voici les modes d'ouverture les plus courants. Ajouter le suffixe + à un mode active à la fois la lecture et l'écriture.

  • r : Lecture seule, pointeur au début. Le fichier doit exister.
  • r+ : Lecture et écriture, pointeur au début. Le fichier doit exister.
  • w : Écriture seule, pointeur au début. Crée le fichier ou écrase son contenu s'il existe.
  • w+ : Lecture et écriture, pointeur au début. Crée le fichier ou écrase son contenu s'il existe.
  • a : Écriture seule, pointeur en fin. Crée le fichier s'il n'existe pas.
  • a+ : Lecture et écriture, pointeur en fin. Crée le fichier s'il n'existe pas.

Si vous désirez plus d'informations, rendez-vous sur la documentation officielle de fopen().

Créer un nouveau fichier

Pour créer un fichier, utilisez fopen() avec un mode qui écrit. Le mode w crée le fichier s'il n'existe pas.

Il faut être prudent lors de l'utilisation du mode w car si le fichier existe déjà, son contenu sera silencieusement écrasé. Si vous souhaitez éviter cela, vous pouvez vérifier l'existence du fichier avec file_exists() avant de l'ouvrir.


                    <?php
                    // Définir le chemin vers le fichier à créer.
                    $cheminFichier = __DIR__ . '/nouveau_fichier.txt';

                    // Vérifier que le fichier n'existe pas déjà pour éviter d'écraser son contenu.
                    if (file_exists($cheminFichier))
                    {
                        // exit() est utilisé ici pour simplifier les exemples.
                        // En pratique, on privilégie des mécanismes plus souples,
                        // comme les exceptions, abordées dans un chapitre ultérieur.
                        exit('Le fichier existe déjà.');
                    }

                    // Ouvrir le fichier en mode "w".
                    // Le fichier est créé s'il n'existe pas.
                    $monFichier = fopen($cheminFichier, 'w');

                    // Vérifier que l'ouverture a réussi.
                    if ($monFichier === false)
                    {
                        exit('Impossible de créer le fichier.');
                    }

                    // Fermer le fichier.
                    fclose($monFichier);
                

Lire le contenu d'un fichier

Lecture ligne par ligne avec fgets()

Dans l'exemple suivant, nous allons afficher chaque ligne contenue dans le fichier "mon_fichier.txt".

Fichier "mon_fichier.txt"


                    Claudy aime les poneys.
                    Jean-Claude est nerveux.
                    Laurence n'aime pas les kékés.
                

Fichier "index.php"


                    <?php
                    // Ouvrir le fichier en lecture.
                    // Le pointeur est placé au début du fichier.
                    $monFichier = fopen(__DIR__ . '/mon_fichier.txt', 'r');

                    // Vérifier que l'ouverture a réussi.
                    if ($monFichier === false)
                    {
                        exit('Impossible d\'ouvrir le fichier.');
                    }

                    // Lire le fichier ligne par ligne.
                    // fgets() lit une ligne et avance le pointeur à la ligne suivante.
                    // Quand il n'y a plus rien à lire, fgets() renvoie false.
                    while (($ligne = fgets($monFichier)) !== false)
                    {
                        // Afficher la ligne lue.
                        echo $ligne;
                        /*
                            Affiche :
                            Claudy aime les poneys.
                            Jean-Claude est nerveux.
                            Laurence n'aime pas les kékés.
                        */
                    }

                    // Fermer le fichier pour libérer la ressource.
                    fclose($monFichier);
                

Description du code précédent :

  • $monFichier = fopen(__DIR__ . '/mon_fichier.txt', 'r') : ouvre le fichier en lecture et renvoie une ressource.
  • if ($monFichier === false) : vérifie que l'ouverture a réussi avant de continuer.
  • while (($ligne = fgets($monFichier)) !== false) : lit une ligne à chaque tour de boucle.
    La comparaison stricte !== est importante. Elle distingue false (fin de fichier) d'une ligne vide qui serait évaluée comme fausse avec !=.
  • echo $ligne : affiche la ligne lue.
  • fclose($monFichier) : ferme la ressource et libère le fichier.

Vérifier si le pointeur a atteint la fin du fichier avec feof()

La fonction feof() permet de vérifier si le pointeur a atteint la fin du fichier. Elle renvoie true quand il n'y a plus rien à lire. Vous la rencontrerez souvent dans d'autres ressources. Elle est parfois utilisée comme condition de boucle, par exemple :


                    <?php
                    $monFichier = fopen(__DIR__ . '/mon_fichier.txt', 'r');

                    if ($monFichier === false)
                    {
                        exit('Impossible d\'ouvrir le fichier.');
                    }

                    // Lire tant que le pointeur n'a pas atteint la fin du fichier.
                    while (!feof($monFichier))
                    {
                        // Lire la ligne courante.
                        $ligne = fgets($monFichier);

                        // fgets() peut renvoyer false si la lecture échoue.
                        if ($ligne !== false)
                        {
                            echo $ligne;
                        }
                    }

                    fclose($monFichier);
                

Les deux approches sont valables. La boucle avec fgets() !== false est plus concise. La boucle avec feof() est plus explicite sur la condition d'arrêt.

Lecture par octets avec fread()

La fonction fgets() lit un fichier ligne par ligne. Cela fonctionne bien pour les fichiers texte, car leur contenu est organisé en lignes séparées par des sauts de ligne.

Mais tous les fichiers ne sont pas des fichiers texte. Une image (JPEG, PNG), un fichier audio (MP3), un document PDF ou un fichier compressé (ZIP) sont des fichiers binaires. Leur contenu n'est pas du texte lisible par un humain, mais des octets bruts structurés selon un format propre au fichier. Dans un fichier binaire, il n'y a pas de notion de "ligne", fgets() n'a donc pas de sens pour les lire.

La fonction fread() résout ce problème. Elle lit un nombre précis d'octets, indépendamment du contenu. Elle est utile dans deux situations principales :

  • Fichiers binaires : Par exemple, lire les premiers octets d'un fichier pour identifier son type réel (les formats binaires commencent généralement par une séquence d'octets fixe qui identifie le format).
  • Fichiers volumineux : Plutôt que de lire ligne par ligne avec fgets(), on peut lire par blocs de taille fixe (ex.: 8 192 octets à la fois). C'est plus performant car chaque appel de lecture a un coût, lire 1 000 lignes courtes demande 1 000 appels, alors que lire le même contenu par blocs de 8 192 octets peut ne demander que quelques appels.

L'exemple suivant lit un fichier par blocs de 8 192 octets et affiche son contenu progressivement.


                    <?php
                    // Ouvrir le fichier en lecture.
                    $monFichier = fopen(__DIR__ . '/fichier_volumineux.txt', 'r');

                    if ($monFichier === false)
                    {
                        exit('Impossible d\'ouvrir le fichier.');
                    }

                    // Lire le fichier par blocs de 8 192 octets.
                    // À chaque tour, fread() lit les 8 192 octets suivants.
                    // Le dernier bloc peut contenir moins d'octets si la taille
                    // du fichier n'est pas un multiple de 8 192.
                    // Quand il n'y a plus rien à lire, fread() renvoie une chaîne vide.
                    while (($bloc = fread($monFichier, 8192)) !== '')
                    {
                        // Traiter le bloc lu (ici, simplement l'afficher).
                        echo $bloc;
                    }

                    // Fermer le fichier.
                    fclose($monFichier);
                

Écrire dans un fichier

La fonction fwrite() écrit une chaîne de caractères dans un fichier ouvert. Elle écrit à l'endroit où se trouve le pointeur, puis avance le pointeur après ce qui a été écrit.

fwrite() attend deux arguments :

  1. la ressource du fichier déjà ouvert (retournée par fopen()),
  2. la chaîne à écrire dans ce fichier.

La fonction renvoie le nombre d'octets écrits, ou false en cas d'erreur.

Le mode d'ouverture détermine le comportement de l'écriture. Avec le mode w, le contenu existant est écrasé. Avec le mode a, le pointeur est placé en fin de fichier et les nouvelles données sont ajoutées après le contenu existant.

Dans l'exemple suivant, nous ouvrons le fichier "mon_fichier.txt" en mode a+ pour ajouter une ligne à la fin, puis nous relisons le contenu mis à jour.


                    <?php
                    // Ouvrir le fichier en mode "a+".
                    // Lecture et écriture, pointeur placé en fin de fichier.
                    // Si le fichier n'existe pas, il est créé.
                    $monFichier = fopen(__DIR__ . '/mon_fichier.txt', 'a+');

                    if ($monFichier === false)
                    {
                        exit('Impossible d\'ouvrir le fichier.');
                    }

                    // Écrire une nouvelle ligne en fin de fichier.
                    // "\n" représente un saut de ligne.
                    fwrite($monFichier, 'Steph est l\'ami de Jean-Claude.' . "\n");

                    // Replacer le pointeur au début pour relire depuis la première ligne.
                    // Sans cette ligne, le pointeur serait resté après ce qu'on vient d'écrire,
                    // et fgets() ne lirait plus rien.
                    rewind($monFichier);

                    // Lire le fichier ligne par ligne.
                    while (($ligne = fgets($monFichier)) !== false)
                    {
                        echo $ligne;
                        /*
                            Affiche :
                            Claudy aime les poneys.
                            Jean-Claude est nerveux.
                            Laurence n'aime pas les kékés.
                            Steph est l'ami de Jean-Claude.
                        */
                    }

                    // Fermer le fichier.
                    fclose($monFichier);
                

Remarque sur les sauts de ligne

Dans l'exemple ci-dessus, nous utilisons "\n" pour insérer un saut de ligne. Ce caractère est le standard sur les systèmes Linux et macOS. Sur Windows, le saut de ligne est représenté par "\r\n".

PHP propose aussi la constante PHP_EOL, qui vaut "\n" sous Linux/macOS et "\r\n" sous Windows. Elle s'adapte automatiquement au système d'exploitation du serveur. Si vous devez garantir un format précis quel que soit le serveur (par exemple pour un fichier CSV ou un protocole réseau), préférez "\n" explicitement.

Se déplacer dans un fichier

Lorsqu'un fichier est ouvert, PHP utilise un pointeur pour savoir où lire ou écrire. À chaque lecture ou écriture, ce pointeur avance automatiquement.

Dans certains cas, cette progression automatique ne suffit pas. On peut vouloir relire un fichier depuis le début, reprendre une lecture à un endroit précis, ou simplement savoir où l'on se trouve. Les fonctions suivantes servent exactement à cela.

rewind()

rewind() sert à revenir au début du fichier. Elle est utilisée quand on a déjà lu ou écrit une partie du fichier et qu'on souhaite le parcourir à nouveau depuis le premier octet.

C'est la solution la plus simple et la plus lisible lorsqu'on veut repartir de zéro, sans se soucier de calculer une position.


                    rewind(resource $monFichierOuvert): bool;
                

fseek()

fseek() permet de placer le pointeur à un endroit précis dans le fichier, exprimé en nombre d'octets. Elle est utile quand on connaît la structure du fichier ou quand on veut accéder directement à une zone donnée.

Contrairement à rewind(), qui ramène toujours au début, fseek() offre un contrôle fin sur la position.


                    fseek(resource $monFichierOuvert, int $decalage, int $origine = SEEK_SET): int;
                
  • SEEK_SET : Le déplacement se fait depuis le début du fichier.
  • SEEK_CUR : Le déplacement se fait depuis la position actuelle.
  • SEEK_END : Le déplacement se fait depuis la fin du fichier.

                    <?php
                    $monFichier = fopen(__DIR__ . '/mon_fichier.txt', 'r');

                    if ($monFichier === false)
                    {
                        exit('Impossible d\'ouvrir le fichier.');
                    }

                    // Sauter les 10 premiers octets du fichier.
                    fseek($monFichier, 10, SEEK_SET);

                    // Lire à partir de cette position.
                    echo fgets($monFichier);

                    // Revenir au début du fichier.
                    rewind($monFichier);

                    fclose($monFichier);
                

ftell()

ftell() sert à connaître la position actuelle du pointeur dans le fichier. Elle est souvent utilisée pour comprendre jusqu'où une lecture a avancé ou pour mémoriser une position avant de se déplacer ailleurs.


                    ftell(resource $monFichierOuvert): int|false;
                

                    <?php
                    $monFichier = fopen(__DIR__ . '/mon_fichier.txt', 'r');

                    if ($monFichier === false)
                    {
                        exit('Impossible d\'ouvrir le fichier.');
                    }

                    // Position initiale.
                    echo ftell($monFichier); // 0

                    // Lecture d'une ligne.
                    fgets($monFichier);

                    // Le pointeur a avancé.
                    echo ftell($monFichier);

                    fclose($monFichier);
                

Verrouiller le fichier

Le verrouillage permet de contrôler l'accès à un fichier quand plusieurs processus peuvent y écrire en même temps. La fonction flock() peut placer un verrou exclusif le temps d'une séquence d'actions.

Important : flock() utilise un verrou consultatif (advisory lock) sur la plupart des systèmes. Cela signifie que le verrou ne fonctionne que si tous les programmes qui accèdent au fichier utilisent également flock(). Un autre script qui écrit dans le même fichier sans appeler flock() ne sera pas bloqué.

Verrou bloquant

Par défaut, flock() avec LOCK_EX est bloquant : si un autre processus détient le verrou, le script attend que le verrou se libère avant de continuer.


                    <?php
                    // Ouvrir le fichier en mode ajout.
                    $monFichier = fopen(__DIR__ . '/mon_fichier.txt', 'a');

                    if ($monFichier === false)
                    {
                        exit('Impossible d\'ouvrir le fichier.');
                    }

                    // Obtenir un verrou exclusif.
                    // Si le fichier est déjà verrouillé par un autre processus,
                    // le script attend ici jusqu'à ce que le verrou soit libéré.
                    flock($monFichier, LOCK_EX);

                    // Le verrou est obtenu : on peut écrire en toute sécurité.
                    fwrite($monFichier, "Steph est l'ami de Jean-Claude." . "\n");

                    // Libérer le verrou pour que les autres processus puissent accéder au fichier.
                    flock($monFichier, LOCK_UN);

                    // Fermer le fichier.
                    fclose($monFichier);
                    ?>
                

Verrou non bloquant

Si vous ne souhaitez pas que le script reste en attente, ajoutez le drapeau LOCK_NB. Dans ce cas, flock() renvoie false immédiatement si le verrou ne peut pas être obtenu.


                    <?php
                    $monFichier = fopen(__DIR__ . '/mon_fichier.txt', 'a');

                    if ($monFichier === false)
                    {
                        exit('Impossible d\'ouvrir le fichier.');
                    }

                    // Tenter d'obtenir un verrou exclusif sans attendre.
                    // LOCK_NB rend l'appel non bloquant.
                    if (flock($monFichier, LOCK_EX | LOCK_NB))
                    {
                        // Le verrou est obtenu : on peut écrire.
                        fwrite($monFichier, "Steph est l'ami de Jean-Claude." . "\n");

                        // Libérer le verrou.
                        flock($monFichier, LOCK_UN);
                    }
                    else
                    {
                        // Le verrou n'a pas pu être obtenu : un autre processus utilise le fichier.
                        echo "Le fichier est actuellement utilisé par un autre processus.";
                    }

                    // Fermer le fichier.
                    fclose($monFichier);
                    ?>
                

Après les opérations, libérez toujours le verrou avec LOCK_UN. Tant que vous ne libérez pas le verrou, les autres processus qui utilisent flock() seront bloqués ou échoueront selon le contexte.

Documentation

Pour aller plus loin, consultez la documentation officielle du système de fichiers PHP dans le manuel PHP.