35 votes

Ajout atomique d'une ligne à un fichier et création d'un fichier s'il n'existe pas

J'essaie de créer une fonction (à des fins de journalisation)

append($file, $data)

que

  1. crée $file s'il n'existe pas et
  2. ajoute de manière atomique $data à elle.

Il doit

  • supporter une forte concurrence,
  • supporte les longues chaînes de caractères et les
  • être aussi performant que possible.

Jusqu'à présent, la meilleure tentative est la suivante :

function append($file, $data)
{
    // Ensure $file exists. Just opening it with 'w' or 'a' might cause
    // 1 process to clobber another's.
    $fp = @fopen($file, 'x');
    if ($fp)
        fclose($fp);

    // Append
    $lock = strlen($data) > 4096; // assume PIPE_BUF is 4096 (Linux)

    $fp = fopen($file, 'a');
    if ($lock && !flock($fp, LOCK_EX))
        throw new Exception('Cannot lock file: '.$file);
    fwrite($fp, $data);
    if ($lock)
        flock($fp, LOCK_UN);
    fclose($fp);
}

Il fonctionne correctement, mais il semble assez complexe. Existe-t-il un moyen plus propre (intégré ?) de le faire ?

75voto

drrcknlsn Points 7727

PHP dispose déjà d'une fonction intégrée pour effectuer cette opération, file_put_contents() . La syntaxe est la suivante :

file_put_contents($filename, $data, FILE_APPEND);

Il convient de noter que file_put_contents() créera le fichier s'il n'existe pas déjà (à condition que vous disposiez des autorisations nécessaires sur le système de fichiers).

4 votes

Je pense que cela n'utilisera pas le mode 'x' pour ouvrir un fichier (O_EXCL en C), ce qui peut créer une condition de course si le fichier n'existe pas. Voir github.com/php/php-src/blob/master/ext/standard/file.c (on dirait qu'il n'utilise que le "c")

11 votes

30 questions et pas une seule réponse. pauvre monde ! :(

0 votes

C'est une mauvaise réponse. Elle ne répond pas correctement à la question : Il demande "y ajoute atomiquement $data" et "supporte une haute concurrence". file_put_contents n'est pas sûr pour les écritures concurrentes.

63voto

catalint Points 419

En utilisant la fonction interne de PHP http://php.net/manual/en/function.file-put-contents.php

file_put_contents($file, $data, FILE_APPEND | LOCK_EX);

FILE_APPEND => drapeau pour ajouter le contenu à la fin du fichier

LOCK_EX => drapeau pour éviter que quelqu'un d'autre écrive dans le fichier en même temps (Disponible depuis PHP 5.1)

0 votes

Cette solution est meilleure que celle qui a été la plus votée.

1 votes

File_put_contents n'est pas sûr pour les écritures conccurentes.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X