2014-05-07 3 views
1

J'ai besoin de regarder un dossier pour les fichiers - les fichiers seront placés dans des dossiers, et il faudra peut-être plusieurs secondes ou quelques minutes pour que la copie de fichiers soit terminée. J'ai lu plusieurs sujets sur SO (Checking File sizes for changes, Detect file in use by other process). Aucun d'entre eux ne donne une bonne réponse.Surveillance des changements de taille de fichier

L'interrogation est "mauvaise", mais comment puis-je savoir si un fichier cesse d'augmenter en taille? Plus précisément, y a-t-il une notification pour "taille de fichier est constante" ou "fichier est complet"? Le système d'exploitation peut-il notifier la non-activité (IOW, comment prouver un négatif?). Il me semble que logiquement, on DOIT interroger un fichier pour voir s'il ne change pas. J'ai également vérifié SCEvents et UKKQueue, mais encore une fois tous les deux notifier d'un changement. UKKQueue a une méthode "taille de fichier augmentée", mais aucune "taille de fichier n'a augmenté la méthode".

Est-il vraiment possible de détecter la fin de la copie de fichier sans interroger ou utiliser sleep()?

Répondre

0

Si vous avez le contrôle sur les fichiers en cours de livraison, copiez-les dans un répertoire temporaire sur le même volume et, une fois la copie terminée, déplacez le fichier. Le mouvement reloue simplement le fichier dans le système de fichiers. Ensuite, kqueue peut vous informer lorsque le fichier est présent. Sa présence signifie que le fichier entier est là. Par ailleurs, lorsque vous utilisez la version «atomiquement» de l'API du gestionnaire de fichiers de cacao, c'est à peu près ce qu'il fait dans les coulisses.

Si vous n'avez aucun contrôle et que vous souhaitez simplement surveiller les fichiers, utilisez kqueue pour vous avertir lorsqu'un fichier apparaît. Au fur et à mesure que le fichier grossit, la file d'attente vous avertira qu'elle a été étendue. Cependant, il ne sait pas si une autre application est faite pour étendre le fichier ou non, donc vous devez toujours avoir une sorte de minuterie pour vérifier le changement.

Je déclencherais une minuterie d'intervalle en même temps Je m'inscris pour les événements kqueue NOTE_EXTEND. Je garderais une trace de la dernière fois que j'ai vu un événement NOTE_EXTEND, et si je n'en avais pas vu depuis le dernier déclenchement, je suppose que le fichier a cessé d'être étendu. Maintenant, vous devez déterminer quelle valeur de temporisateur utiliser ... et si vous voulez reculer et continuer à chercher un "while" mais à moins que l'application copiant le fichier le fasse via un "move" ou à moins envoie une notification que le fichier a été entièrement copié, vous allez devoir faire un certain type de minuterie, avec une valeur arbitraire ... à quel moment vous supposez que c'est fait. De toute évidence, si vous pouvez intégrer la première option, les choses vont beaucoup mieux car vous avez une façon déterministe de savoir que le fichier a cessé de croître.

+0

Oui, mon application surveille un dossier réseau et n'a aucun contrôle sur les fichiers qui vont apparaître. –

0

C'est le code que j'ai utilisé pour surveiller le fichier localement. Je ne suis pas sûr que cela fonctionnerait pour vous.

int fileHander = open("/location/file", O_RDONLY); 
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0); 
    unsigned long mask = DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_EXTEND | DISPATCH_VNODE_ATTRIB | DISPATCH_VNODE_LINK | DISPATCH_VNODE_RENAME | DISPATCH_VNODE_REVOKE; 
    __block dispatch_source_t source; 

    void (^changeHandler)(void) = ^{ 
    unsigned long l = dispatch_source_get_data(source); 
    if (l & DISPATCH_VNODE_DELETE) { 
     printf("file deleted"); 
     dispatch_source_cancel(source); 
    } 
    else { 

     printf("file data changed"); 
    } 
    }; 
    void (^cancelHandler)(void) = ^{ 
    int fileHander = dispatch_source_get_handle(source); 
    close(fileHander); 
    }; 

    source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE,fileHander, mask, queue); 
    dispatch_source_set_event_handler(source, changeHandler); 
    dispatch_source_set_cancel_handler(source, cancelHandler); 
    dispatch_resume(source); 
Questions connexes