2010-11-18 34 views
2

J'ai le code exemple suivantPHP fwrite renvoie toujours le nombre d'octets à écrire même si le fichier n'existe pas, est ce comportement attendu?

<?php 
`echo test > /tmp/test.txt`; 
$f=fopen("/tmp/test.txt","w+"); 
`rm /tmp/test.txt`; 
var_dump(fwrite($f,"test")); 
fclose($f); 
file_get_contents("/tmp/test.txt"); 

Ce qui crée un fichier, ouvre un pointeur vers elle, supprime le fichier tente ensuite d'écrire. Maintenant, je me attends fwrite pour revenir faux ou 0 car aucune donnée ne sera écrite, mais il produit la sortie suivante

int(4) 

Warning: file_get_contents(/tmp/test.txt): failed to open stream: No such file or directory in /Stuff/tmp/test3 on line 7 

Ainsi, le fwrite réussit apparemment, mais les file_get_contents échoue comme prévu.

Est-ce que le comportement de fwrite devrait renvoyer le nombre d'octets à écrire? Si oui, comment puis-je tester si l'écriture a vraiment réussi?

est avec php 5.3.3

Répondre

5

La raison pour laquelle il est de retour false est que le pointeur de fichier est à la fin du fichier après fwrite ... C'est ce que fgets est censé faire quand il atteint la fin du fichier (il retourne false car il est plus de données à obtenir) ...

Ce que vous devez faire est d'ajouter un appel fseek avant d'appeler fgets:

var_dump(fwrite($f,"test")); 
fseek($f, 0); 
var_dump(fgets($f)); 

Edit: Maintenant que je comprends votre question (et l'ai regardé):

Très bien, alors voici ce qui se passe. Pour comprendre, vous devez d'abord savoir comment fonctionnent les systèmes de fichiers Linux. Le nom du fichier n'a aucun sens pour le système d'exploitation. Tout ce qu'il fait est pointez sur le INODE pour le fichier. L'inode stocke les données, etc. Il stocke également un numéro de référence au numéro hard-links dans ce fichier. Le fichier n'est supprimé que lorsque le numéro de référence tombe à 0. Je soupçonne que l'ouverture d'un pointeur sur le fichier (en utilisant fopen, ou d'autres appels système) augmente le nombre de références.

Donc, fondamentalement, cela signifie que lorsque vous avez exécuté rm sur le fichier, il a supprimé le lien physique. Mais puisque le fichier était encore ouvert, vous pouviez toujours accéder à l'inode via fwrite (d'où la réussite de l'écriture). Vous ne pouviez pas accéder à /tmp/test.txt car le lien physique vers ce nom de fichier n'existait plus. Ainsi, le fichier est devenu un fichier fantôme qui n'est accessible que par l'inode. Mais dès que vous avez fermé le handle de fichier pour ce fichier (fclose, ou en terminant le script) le nombre de références est tombé à 0 et l'inode a été libéré ...

Donc le fichier existe, il n'est pas accessible depuis le nom de fichier après que vous appelez rm ...

C'est juste ce que je rassemble en sachant ce que je sais sur les systèmes de fichiers. Je ne dis pas que c'est 100% précis, mais ça devrait être une hypothèse décente ...

+0

+1 Battu au coup de poing –

+0

J'ai modifié la question pour la rendre plus claire, il ne s'agit pas des fgets, il est écrit fwrite écrit 4 octets dans un fichier qui n'existe pas, ne devrait pas écrire fwrite 0 ou false? – Rwky

+0

+1 rewind ($ f) fonctionnera également (se rapportant à la question originale). – GZipp

0

Le code suivant devrait vous permettre de vérifier si elle était une écriture réussie.

if (fwrite($handle, $somecontent) === FALSE) { 
     echo "Cannot write to file ($filename)"; 
     exit; 
} 
+0

Mais 'var_dump' montre que' 4' a été retourné, indiquant que 4 octets ont été écrits. Donc, ce contrôle n'indiquerait pas une erreur dans ce cas (ne pas dire que c'est mauvais, ne s'applique pas à ce problème) ... – ircmaxell

+0

Le var_dump ne montre pas la sortie fwrite comme 4 qui n'est pas fausse. – Rwky

0

Je crois que vous devez d'abord enregistrer le fichier

fclose($f); 
+0

La fermeture du fichier n'est pas la même chose que la sauvegarde. Cela force une chasse d'eau, mais vous n'avez pas besoin de la fermer pour forcer la chasse d'eau. Et étant donné qu'il est tamponné, il suffit de vider pour voir les changements d'un autre processus. De plus, vous pouvez simplement utiliser la commande ['fflush'] (http://us3.php.net/manual/fr/function.fflush.php) au lieu de fermer et rouvrir le fichier ... – ircmaxell

0

Votre code a besoin de conditions, par exemple erreur de manipulation

  • vérifier si le fichier existe
  • si le fichier est accessible en écriture
  • si les données ont été écrites dans le fichier
  • si les données sont lisibles
+0

Ceci est juste un exemple code, ma question est en ce qui concerne le fwrite est-ce le comportement attendu pour qu'il revienne qu'il a écrit 4 octets à un fichier inexistant ne devrait-il pas retourner 0 ou faux? – Rwky

2

Si cela est sur un serveur Linux (et éventuellement d'autres OS unix-like), la référence au fichier dans le système de fichiers est supprimée par rm, mais le fichier lui-même existe toujours jusqu'à ce que tous les programmes de lecture/écriture soient fermés.

Ceci est dû à la façon dont fonctionne hard links; toutes les entrées du système de fichiers sont des liens physiques, soft links, ou des périphériques.

+0

Incidemment, Windows va juste jeter une erreur si vous essayez de supprimer un fichier pendant qu'un autre processus est en train de lire/écrire. – Powerlord