2010-04-13 5 views
2

Pour un devoir particulier, j'implémente un système de stockage de données de base utilisant des fichiers séquentiels sous la norme C, qui ne peut pas charger plus d'un enregistrement à la fois. Ainsi, la partie de base crée un nouveau fichier où les résultats de tout ce que nous faisons avec les enregistrements originaux sont stockés. Le fichier précédent est renommé et un nouveau sous le nom de travail est créé. Le code est compilé avec MinGW 5.1.6 sur Windows 7.stdio's remove() ne supprime pas toujours à l'heure

Le problème est, cette version particulière du code (j'ai des versions presque identiques de ce flottant autour de mes fonctions) ne supprime pas toujours l'ancien fichier, donc le renommage échoue et donc les données stockées sont effacées par le fopen().

FILE *archivo, *antiguo; 

remove("IndiceNecesidades.old"); // This randomly fails to work in time. 
rename("IndiceNecesidades.dat", "IndiceNecesidades.old"); // So rename() fails. 

antiguo = fopen("IndiceNecesidades.old", "rb"); 
// But apparently it still gets deleted, since this turns out null (and I never find the .old in my working folder after the program's done). 
archivo = fopen("IndiceNecesidades.dat", "wb"); // And here the data gets wiped. 

En fait, chaque fois que le .old existe déjà, il y a une chance qu'il est pas retiré à temps pour le changement de nom() pour prendre effet avec succès. Aucun nom possible n'est en conflit à la fois interne et externe.

La chose étrange est que c'est seulement avec ce fichier particulier. Les snippets identiques à l'exception du nom changé en Necesidades.dat (qui se produit dans 3 fonctions différentes) fonctionnent parfaitement.

// I'm yet to see this snippet fail. 
FILE *antiguo, *archivo; 

remove("Necesidades.old"); 
rename("Necesidades.dat", "Necesidades.old"); 

antiguo = fopen("Necesidades.old", "rb"); 
archivo = fopen("Necesidades.dat", "wb"); 

Toutes les idées sur pourquoi cela se produit, et/ou comment puis-je assurer la commande remove() a pris effet par le changement de nom de temps() est exécutée? (Je pensais juste utiliser une boucle while pour forcer l'appel remove() tant que fopen() renvoie un pointeur non nul, mais cela ressemble à un plantage dû au débordement de l'OS avec des demandes de suppression ou quelque chose.)

+0

Vérifiez-vous la valeur de retour de remove? Et avez-vous toujours le fichier ouvert lorsque vous essayez de le supprimer? – Cascabel

+0

Supprimer montre pas de problèmes (et en fait supprime le fichier, juste le fait trop tard), Rename se révèle "Permission Denied" (qui est parce que .old existe toujours, vérifié cela avec un test fopen()). Impossible d'ouvrir le fichier. – Kyte

+0

Ouais, je pensais que vous n'aviez pas oublié quelque chose d'aussi évident, mais ça valait le coup. – Cascabel

Répondre

3

Alors soudainement, après avoir lu la mention de Scott des autorisations, je pensais à « Autorisation refusée » et appliqué certains Google. Turned out it's a pretty common, if obscure, error. caf avait raison, c'était dans un autre morceau de code. A savoir, j'avais oublié de fermer ce même fichier dans la fonction destinée à montrer le contenu. Comme je ne suivais pas ce détail particulier, il semblait être aléatoire.

Clause de non-responsabilité: Les tâches de calcul hebdomadaires font très peu de place au sommeil. ¬¬

+2

Juste un fait intéressant: si vous utilisiez le système POSIX et non Windows ce problème ne se produirait pas. Dans le système POSIX, vous pouvez toujours supprimer un fichier ouvert et il sera supprimé du répertoire, même si, en même temps, il existera, sans nom, jusqu'à ce que le dernier processus le ferme. Juste une des différences entre la famille Windows et POSIX. –

1

Il serait probablement une bonne idée de vérifier la fonction remove() pour les erreurs. man remove indique que la fonction renvoie 0 en cas de succès et -1 en cas d'erreur, en définissant errno pour enregistrer l'erreur. Essayez de remplacer l'appel par

if (remove("IndiceNecesidades.old") != 0){ 
    perror("remove(\"IndiceNecesidades.old\") failed"); 
} 

qui devrait donner un message d'erreur indiquant ce qui a échoué.

En outre, il ne semble pas que la supprimer neccessaire

changement de nom de l'homme()

L'appel système Rename() le lien nommé vieux pour être renommé en tant que nouveau. Si une nouvelle existe, elle est d'abord supprimée. Les anciens et les nouveaux doivent être du même type (les deux doivent être des répertoires ou des non-répertoires) et doit résider sur le même système de fichiers.

Le changement de nom() garantit des appels système qu'une instance de nouvelle aura toujours exister, même si le système doit tomber en panne au milieu de l'opération.

Si le dernier élément de l'ancien est un lien symbolique , le lien symbolique est renommé, pas le fichier ou le répertoire à lequel il pointe.

EPERM sera retourné si:

[EPERM] Le répertoire contenant ancien est marqué collant et ni le répertoire contenant ni anciens sont la propriété de l'utilisateur effectif ID.

[EPERM] Le nouveau fichier existe, le répertoire contenant nouveau est marqué collant, et ni le répertoire contenant ni nouvelles sont la propriété par l'effi- ID utilisateur tive.

la prochaine étape serait de vérifier que vous disposez des autorisations sur le répertoire contenant

+0

J'ai perror'd à la fois supprimer et renommer, seulement renommer renvoie des erreurs. (De plus, la suppression se poursuit toujours.) btw: Vous avez votre état à l'envers là-bas. 0 est faux. ;) – Kyte

+0

@Kyte: Non, il a la condition correcte. ISO C spécifie que remove() renvoie 0 en cas de succès et -1 en cas d'échec, comme il le dit. – janneb

+0

@janneb, Il y avait une faute de frappe mais je l'ai attrapé juste après avoir soumis la réponse, Kyte doit l'avoir vu dans l'écart. –

1

Cela semble assez étrange, et encore plus quand vous dites que le même code fonctionne bien avec un nom différent - je voudrais fortement suspect un bug ailleurs dans votre code. Cependant, vous devriez être en mesure de travailler autour d'elle en renommant le fichier que vous souhaitez supprimer:

rename("IndiceNecesidades.old", "IndiceNecesidades.older"); 
remove("IndiceNecesidades.older"); 
rename("IndiceNecesidades.dat", "IndiceNecesidades.old"); 
Questions connexes