web-dev-qa-db-fra.com

Quelle est la bonne façon d'utiliser inotify?

Je souhaite utiliser le mécanisme inotify sous Linux. Je souhaite que mon application sache quand un fichier aaa a été modifié. Pouvez-vous s'il vous plaît me fournir un échantillon comment faire cela?

21
dubila

L'API inotify C 

inotify fournit trois appels système pour créer des moniteurs de système de fichiers de tous types: 

  • inotify_init() crée une instance du sous-système inotify dans le noyau et renvoie un descripteur de fichier en cas de succès et -1 en cas d'échec. Comme pour les autres appels système, si inotify_init() échoue, cochez errno pour obtenir un diagnostic.
  • inotify_add_watch(), comme son nom l'indique, ajoute un watch. Chaque veille doit fournir un chemin d'accès et une liste d'événements pertinents, chaque événement étant spécifié par une constante, telle que IN_MODIFY. Pour surveiller plusieurs événements, utilisez simplement l'opérateur logique ou - l'opérateur pipe (|) en C - entre chaque événement. Si inotify_add_watch() réussit, l'appel renvoie un identifiant unique pour la surveillance enregistrée; sinon, il retourne -1. Utilisez l'identifiant pour modifier ou supprimer la montre associée. 
  • inotify_rm_watch() supprime une montre.

Les appels système read() et close() sont également nécessaires. Etant donné le descripteur généré par inotify_init(), appelez read() pour attendre les alertes. En supposant un descripteur de fichier typique, l’application est bloquée dans l’attente de la réception des événements, qui sont exprimés sous forme de données dans le flux. La clôture commune () sur le descripteur de fichier générée par inotify_init() supprime et libère toutes les montres actives ainsi que toute la mémoire associée à l'instance inotify. (La mise en garde typique relative au nombre de références s'applique également ici. Tous les descripteurs de fichier associés à une instance doivent être fermés avant que la mémoire utilisée par les contrôles et par inotify ne soit libérée.)

#include "inotify.h"  
#include "inotify-syscalls.h"  
int wd;   
wd = inotify_add_watch (fd,   
            "/home/rlove/Desktop", IN_MODIFY | IN_CREATE | IN_DELETE);
if (wd < 0)
      perror ("inotify_add_watch");

Cet exemple ajoute une surveillance sur le répertoire/home/rlove/Desktop pour toute modification, création ou suppression de fichier.

25
joschi

Vous trouverez ci-dessous un extrait de la manière dont vous pouvez utiliser inotify pour regarder "aaa". Notez que je n'ai pas testé cela, je ne l'ai même pas compilé! Vous devrez ajouter une vérification d'erreur.

Au lieu d'utiliser une lecture bloquante, vous pouvez également utiliser poll/select sur inotfd.

const char *filename = "aaa";
int inotfd = inotify_init();

int watch_desc = inotify_add_watch(inotfd, filename, IN_MODIFY);

size_t bufsiz = sizeof(struct inotify_event) + PATH_MAX + 1;
struct inotify_event* event = malloc(bufsiz);

/* wait for an event to occur */
read(inotfd, event, bufsiz);

/* process event struct here */
9
Fabian

pourquoi réinventer la roue? il existe déjà une application appelée inotifywait qui surveille les fichiers à l'aide de inotify

du terminal 1

# touch cheese
# while inotifywait -e modify cheese; do 
>   echo someone touched my cheese
> done

du terminal 2

echo lol >> cheese

voici ce que l'on voit sur le terminal 1

Setting up watches.
Watches established.
cheese MODIFY 
someone touched my cheese
Setting up watches.
Watches established.
1
activedecay

Comme la question initiale semble mentionner Qt en tant que balise, comme indiqué dans plusieurs commentaires ici, les moteurs de recherche peuvent vous avoir menés ici.

Si quelqu'un veut savoir comment le faire avec Qt, voir http://doc.qt.io/qt-5/qfilesystemwatcher.html pour la version Qt. Sous Linux, il utilise un sous-ensemble d'Inotify. S'il est disponible, reportez-vous à l'explication fournie sur la page Qt pour plus de détails.

Fondamentalement, le code nécessaire ressemble à ceci:

dans mainwindow.h ajouter:

QFileSystemWatcher * watcher;
private slots:
    void directoryChanged(const QString & path);
    void fileChanged(const QString & path);

et pour mainwindow.cpp:

#include <QFileInfo>
#include <QFileSystemWatcher>

watcher = new QFileSystemWatcher(this);
connect(watcher, SIGNAL(fileChanged(const QString &)), this, SLOT(fileChanged(const QString &)));
connect(watcher, SIGNAL(directoryChanged(const QString &)), this, SLOT(directoryChanged(const QString &)));
watcher->addPath("/tmp/"); // watch directory
watcher->addPath("/tmp/a.file");  // watch file

ajoutez également les slots dans mainwindow.cpp qui sont appelés si un changement de fichier/répertoire est remarqué:

void MainWindow::directoryChanged(const QString & path) {
     qDebug() << path;
}
void MainWindow::fileChanged(const QString & path) {
     qDebug() << path;
}
0
user2567875