2009-02-03 4 views
2

J'ai ouvert un flux de fichier vers un très gros fichier en utilisant fopen. Avant d'effectuer une opération de lecture sur ce flux, j'ai supprimé le fichier en utilisant unlink(). Et encore, j'ai été capable de lire tout le fichier.La fread est-elle possible après la suppression d'un fichier?

Je suppose qu'il existe un tampon associé au flux, qui contient les données du fichier. Mais évidemment, ce tampon aura une limite. C'est la raison pour laquelle j'ai choisi a_big_file dont la taille était 551126688 octets ou 526MB.

Je veux savoir quelle est la raison exacte derrière cela. Voici le code de test que j'ai utilisé.

#include <stdio.h> 
#include <unistd.h> 

int main(){ 

    FILE *fp; 
    long long int file_size = 0; 
    int bytes_read = 0; 
    char buf[1]; 

    fp = fopen("a_big_file", "r"); 

    unlink("a_big_file"); 

    while(0 != (bytes_read = fread(buf, 1, 1, fp))){ 
     file_size += bytes_read; 
    } 

    printf("file_size is %llu\n", file_size); 

    return 0; 
} 

Sortie: file_size est 551126688

+0

Jeez ... mes yeux sont de se dégrader. Je pensais que "FRED est possible ..." – StingyJack

+0

FRED était l'éditeur pour Macintosh Common Lisp, et Digitool n'a jamais réussi à passer à OSX. Malheureusement, je ne sais pas que c'est encore possible sur un Macintosh moderne, même si une grande partie de MCL survit. –

Répondre

17

Dans les systèmes d'exploitation Unix et Unix, le fichier ne disparaît pas vraiment jusqu'à ce que le dernier fichier ouvert sur elle est fermée. C'est une astuce très utile pour les fichiers temporaires - si vous le déconnectez dès que vous l'ouvrez, le fichier ne sera pas visible pour les autres processus, et il sera supprimé du système dès que votre programme le ferme, se termine ou des accidents. Cela permet d'éviter la prolifération des fichiers temporaires orphelins. Pratiquement (en passant en revue quelques détails techniques ici), les systèmes de fichiers Unix sont comptés. Lorsque vous ouvrez le fichier, vous êtes réellement connecté à l'inode du fichier (qui est l'indication réelle de l'endroit où le contenu réel du fichier vit). Mais dissocier le fichier supprime simplement l'entrée du répertoire, de sorte que le fichier n'a plus de nom. Le système de fichiers récupérera seulement l'espace de fichier (c.-à-d. L'inode) s'il n'est dans aucune entrée de répertoire, ET que personne ne l'a ouvert. Les autres processus ne peuvent pas l'ouvrir de la manière habituelle car ils ne peuvent pas associer un nom de fichier à l'i-noeud.

Notez que les systèmes de fichiers Unix permettent à plusieurs entrées d'annuaire de pointer vers le même inode - nous appelons cela un "lien dur". Si vous faites un "ls -l", l'un des champs est le nombre de liens durs vers ce même inode, et si vous faites un "ls -li", vous pouvez voir l'adresse inode réelle.

+0

Ok c'est une réponse rapide :), mais je suis curieux de savoir ce qui se passe exactement dans le système. Je suis intéressé à savoir pourquoi les autres processus ne peuvent pas voir le fichier. Je veux dire ce qui se passe en interne, pouvez-vous faire la lumière :) –

+0

Parce qu'il n'y a plus de nom de fichier pointant vers l'inode. Donc, si vous avez déjà un handle de fichier, vous pouvez toujours l'utiliser (dans n'importe quel processus), mais vous ne pouvez plus en obtenir un nouveau. – puetzk

+0

Maintenant, si je comprends bien, supprimer une entrée du système de fichiers signifie supprimer un inode. Cela signifie-t-il que l'emplacement pointé par cet inode contient des données incohérentes, car il peut être écrit par n'importe quel nouveau fichier (créé après unlink)? –

9

De la page de manuel pour unlink:

unlink() supprime un nom du système de fichiers . Si ce nom était le dernier lien vers un fichier et aucun processus ont le fichier ouvrir le fichier est supprimé et l'espace utilisé était disponible pour une réutilisation.

Si le nom était le dernier lien vers un fichier, mais tous les processus ont encore le fichier ouvrir le fichier restera en existence jusqu'à ce que le dernier fichier descripteur se référant à elle est fermée.

Le bit en gras explique le comportement. :-)

[modifier] BTW vous devriez vraiment fermer le fichier avec fclose() avant la déclaration de retour ... [/ modifier]

+0

Que se passerait-il si je ne fais pas de fclose (fp) avant le retour. Lorsque le processus se termine, fp n'a pas de signification à mesure que l'espace d'adressage du processus est libéré. Corrigez-moi si je me trompe. –

+0

1) si vous écrivez, au lieu de lire, les derniers bits de sortie bufférisée pourraient être perdus 2) Si vous étiez un thread au lieu d'un processus, le handle de fichier resterait ouvert 3) c'est un mauvais style car il fait le Le lecteur s'arrête et réfléchit si (1) ou (2) s'applique, ou si c'est inoffensif. – puetzk

+0

De toute façon, le système d'exploitation ne se soucie pas de vos E/S de fichiers tamponnés idiotes - tout ce qui compte c'est que vous avez un descripteur de fichier ouvert, et vous êtes mort, il peut donc fermer le fd (et dissocier le fichier). – ephemient

0

Dans Linux, le fichier est vraiment retiré que lorsque sa dernière poignée ouverte est fermé.

Les gens utilisent généralement des fichiers temporaires de cette façon: mkstemp(3) suivi immédiatement de unlink(2). De cette façon, vous seul pouvez accéder aux données du fichier, aucun autre processus ne peut.

Même si un autre processus crée un autre fichier portant le même nom, le nouveau fichier n'aura rien en commun avec le fichier d'origine.

3

Sur certains systèmes, tels que Linux, vous pouvez facilement accéder aux fichiers qui n'ont pas de nom sur le système de fichiers tant qu'un processus l'a toujours ouvert. Il y a une liste de descripteurs de fichiers dans

/proc/<pid>/fd 

Modifier: Selon le commentaire de Paul Tomblin, vous ne pouvez accéder à ce répertoire si vous êtes le même utilisateur que le processus ou la racine.

Par exemple:

# Create a file with cat 
[email protected]:~$ cat > MYFILE 
Hello 

# Suspend the process and find its pid 
[1]+ Stopped     cat > MYFILE 
[email protected]:~$ ps waux | grep cat 
chris  1311 0.0 0.0 5088 668 pts/6 T 14:29 0:00 cat 
chris  1313 0.0 0.0 5168 840 pts/6 R+ 14:29 0:00 grep cat 

# Inspect the list of open files 
[email protected]:~$ cd /proc/1311/fd 
[email protected]:/proc/1311/fd$ ls -l 
total 0 
lrwx------ 1 chris chris 64 2009-02-03 14:29 0 -> /dev/pts/6 
l-wx------ 1 chris chris 64 2009-02-03 14:29 1 -> /home/chris/MYFILE 
lrwx------ 1 chris chris 64 2009-02-03 14:29 2 -> /dev/pts/6 

# View MYFILE from the symlink on the /proc pseudofilesystem. 
[email protected]:/proc/1311/fd$ cat 1 
Hello 

# Delete the filename /home/chris/MYFILE 
[email protected]:/proc/1311/fd$ rm /home/chris/MYFILE 
[email protected]:/proc/1311/fd$ cat /home/chris/MYFILE 
cat: /home/chris/MYFILE: No such file or directory 

# But the process still has it open. 
# The /proc system knows the original name was deleted 
[email protected]:/proc/1311/fd$ ls -l 
total 0 
lrwx------ 1 chris chris 64 2009-02-03 14:29 0 -> /dev/pts/6 
l-wx------ 1 chris chris 64 2009-02-03 14:29 1 -> /home/chris/MYFILE (deleted) 
lrwx------ 1 chris chris 64 2009-02-03 14:29 2 -> /dev/pts/6 

# We can still view the file, useful for debugging. 
[email protected]:/proc/1311/fd$ cat 1 
Hello 
+0

De quelles autorisations avez-vous besoin pour accéder à ces données? Je pense que vous auriez besoin d'être soit le même utilisateur que commencé le processus ou la racine? –

+0

Oui, c'est exact, je vais ajouter cela à ma réponse, merci. – Chris

Questions connexes