Sapere se un file di nome sconosciuto è stato creato o distrutto
Può accadere che si voglia sapere se un qualsiasi file, del quale non è conosciuto a priori il nome, sia stato creato o distrutto all'interno di una determinata Cartella.
Per mostrare un primo esempio meramente dimostrativo, faremo l'esempio della immediata verifica della creazione nella cartella "/dev/pts" del file speciale di tipo pts di un Terminale nel momento in cui tale Terminale viene aperto:
Public Sub Form_Open() Dim b As Byte Dim ss As New String[] Dim s, dr As String dr = "/dev/pts" ' Assegna ad una variabile vettoriale il nome dei file presenti nella cartella "/dev/pts": b = Dir(dr, Null, gb.Device).Copy() ' Resta in attesa sino a quando un Terminale non è stato aperto: Repeat Wait 0.01 Until Dir(dr, Null, gb.Device).Count = ss.Count + 1 ' Effettua la verifica di quale file speciale di tipo "pts" corrisponde a quello del Terminale appena aperto: ' il nuovo file "pts", non presente nella variabile vettore di tipo stringa, è quello del Terminale: For Each s In Dir(dr, Null, gb.Device) If Not ss.Exist(s) Then Exit Next Print s End
Indice
Verificare la creazione e/o la distruzione di un file
Per verificare se un elemento sia stato creato oppure distrutto, se già esistente, all'interno di una cartella, è possibile utilizzare almeno due modalità.
Uso della Classe Watch
La prima modalità prevede l'uso della Classe "Watch" mediante l'attivazione del Componente "gb.inotify".
Mostriamo un esempio pratico:
Private w As Watch Public Sub Main() w = New Watch("/tmp") As "Cartella" End Public Sub Cartella_Create() Print "Creato: "; Watch.Name End Public Sub Cartella_Delete() Print "Distrutto: "; Watch.Name End
Uso della Classe Timer
Quest'altra modalità prevede l'uso della Classe Timer per verificare la creazione e/o la distruzione di un file all'interno ad esempio della Cartella "/tmp". L'uso dell'oggetto Timer, ci consentirà di non chiudere il programma all'interno di un ciclo infinito.
Private tempus As Timer Private ss As New String[] Private dr As String Public Sub Main() Dim b As Byte Dim ss As New String[] dr = "/tmp" ss = Dir(dr, Null, gb.File).Copy() With tempus = New Timer As "Tempus" .Delay = 100 .Start End With End Public Sub Tempus_Timer() Dim b As Byte Dim s As String If ss.Count <> Dir(dr, Null, gb.File).Count Then For Each s In Dir(dr, Null, gb.File) If Not ss.Exist(s) Then Print "\nCreato il file: "; s ss = Dir(dr, Null, gb.File).Copy() Endif Next For Each s In ss If Not Exist(dr &/ s) Then Print "\nDistrutto il file: "; s ss = Dir(dr, Null, gb.File).Copy() Endif Next Endif End
Uso delle risorse del API di inotify
E' possibile anche utilizzare le risorse inotify, dichiarate nel file header sys/inotify.h .
Va ricordato che vari pseudo-filesystem come "/proc", "/sys" e "/dev/pts" non sono monitorabili con inotify.
Mostriamo un esempio, nel quale si verificheranno la creazione e la distruzione di un determinato file mediante due Button:
Private Const BUFFER As Long = 4096 Private bo As Boolean Library "libc:6" Public Struct inotify_event wd As Integer mask As Integer cookie As Integer lenI As Integer name[32] As Byte End Struct Public Struct pollfd fd As Integer events As Short revents As Short End Struct Private Const IN_ACCESS As Integer = 1 ' File was accessed. Private Const IN_MODIFY As Integer = 2 ' File was modified. Private Const IN_ATTRIB As Integer = 4 ' Metadata changed. Private Const IN_CLOSE_WRITE As Integer = 8 ' Writtable file was closed. Private Const IN_CLOSE_NOWRITE As Integer = &10 ' Unwrittable file closed. Private Const IN_OPEN As Integer = &20 ' File was opened. Private Const IN_MOVED_FROM As Integer = &40 ' File was moved From X. Private Const IN_MOVED_TO As Integer = &80 ' File was moved To Y. Private Const IN_CREATE As Integer = &100 ' Subfile was created. Private Const IN_DELETE As Integer = &200 ' Subfile was deleted. Private Const IN_DELETE_SELF As Integer = &400 ' Self was deleted. Private Const IN_MOVE_SELF As Integer = &800 ' Self was moved. Private Const IN_UNMOUNT As Integer = &2000 ' Backing fs was unmounted. Private Const IN_Q_OVERFLOW As Integer = &4000 ' Event queued overflowed. Private Const IN_IGNORED As Integer = &8000 ' File was ignored. Private Const IN_ISDIR As Integer = &40000000 ' Event occurred against dir. Private Const IN_ALL_EVENTS As Integer = 4095 Private Const POLLIN As Short = 1 ' int inotify_init (void) ' Create and initialize inotify instance. Private Extern inotify_init() As Integer ' int inotify_add_watch (int __fd, const char *__name, uint32_t __mask) ' Add watch of object NAME to inotify instance FD. Private Extern inotify_add_watch(__fd As Integer, name As String, __mask As Integer) As Integer ' int inotify_rm_watch (int __fd, int __wd) ' Remove the watch specified by WD from the inotify instance FD. Private Extern inotify_rm_watch(__fd As Integer, __wd As Integer) As Integer ' int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout) ' Poll the file descriptors described by the NFDS structures starting at FDS. Private Extern poll(__fds As Pollfd, __nfds As Long, __timeout As Integer) As Integer ' ssize_t read (int __fd, void *__buf, size_t __nbytes) ' Read NBYTES into BUF from FD. Private Extern read_C(__fd As Integer, __buf As Pointer, __nbytes As Long) As Long Exec "read" ' int close (int __fd) ' Close the file descriptor FD. Private Extern close_C(__fd As Integer) As Integer Exec "close" Public Sub Form_Open() Dim percorso_file As String Dim fd, wa As Integer Dim buf, p As Pointer Dim letti As Long Dim evento As New Inotify_event Dim pl As New Pollfd Me.Show ' == Poniamo sotto osservazione la Cartella "/tmp", qualora venga creato o venga distrutto un file == percorso_file = "/tmp" fd = inotify_init() If fd = -1 Then Error.Raise("Impossibile inizializare 'inotify' !") wa = inotify_add_watch(fd, percorso_file, IN_ALL_EVENTS) If wa = -1 Then Error.Raise("Errore alla funzione esterna 'inotify_add_watch()' !") Print "Cartella '"; percorso_file; "' ...sotto osservazione !\n" buf = Alloc(CInt(BUFFER)) While bo = False pl.fd = fd pl.events = POLLIN letti = poll(pl, 1, 100) Select Case letti Case -1 Error.Raise("Errore alla funzione esterna 'poll()' !") Case 1 letti = read_C(fd, buf, BUFFER) If letti = -1 Then Error.Raise("Errore alla funzione esterna 'read_C()' !") End Select p = buf While p < buf + CInt(letti) evento = p If evento.mask And IN_CREATE Then Print "Creato il nuevo file: "; String@(evento.name.Data) If evento.mask And IN_DELETE Then Print "Eliminato il file: "; String@(evento.name.Data) If evento.mask And IN_MOVED_FROM Then Print "Spostato nel cestino il file: "; String@(evento.name.Data) p += 16 + evento.lenI Wend Wait 0.1 Wend ' Libera memoria in chiusura: Free(buf) inotify_rm_watch(fd, wa) close_C(fd) Me.Close End Public Sub Button1_Click() ' Va in chiusura... bo = True End
Il precedente codice può essere ovviamente inserito - con le dovute variazioni - anche in un'applicazione a riga di comando:
Private Const BUFFER As Long = 4096 Private bo As Boolean Library "libc:6" Public Struct inotify_event wd As Integer mask As Integer cookie As Integer lenI As Integer name[32] As Byte End Struct Public Struct pollfd fd As Integer events As Short revents As Short End Struct Private Const IN_ACCESS As Integer = 1 ' File was accessed. Private Const IN_MODIFY As Integer = 2 ' File was modified. Private Const IN_ATTRIB As Integer = 4 ' Metadata changed. Private Const IN_CLOSE_WRITE As Integer = 8 ' Writtable file was closed. Private Const IN_CLOSE_NOWRITE As Integer = &10 ' Unwrittable file closed. Private Const IN_OPEN As Integer = &20 ' File was opened. Private Const IN_MOVED_FROM As Integer = &40 ' File was moved From X. Private Const IN_MOVED_TO As Integer = &80 ' File was moved To Y. Private Const IN_CREATE As Integer = &100 ' Subfile was created. Private Const IN_DELETE As Integer = &200 ' Subfile was deleted. Private Const IN_DELETE_SELF As Integer = &400 ' Self was deleted. Private Const IN_MOVE_SELF As Integer = &800 ' Self was moved. Private Const IN_UNMOUNT As Integer = &2000 ' Backing fs was unmounted. Private Const IN_Q_OVERFLOW As Integer = &4000 ' Event queued overflowed. Private Const IN_IGNORED As Integer = &8000 ' File was ignored. Private Const IN_ISDIR As Integer = &40000000 ' Event occurred against dir. Private Const IN_ALL_EVENTS As Integer = 4095 Private Const POLLIN As Short = 1 ' int inotify_init (void) ' Create and initialize inotify instance. Private Extern inotify_init() As Integer ' int inotify_add_watch (int __fd, const char *__name, uint32_t __mask) ' Add watch of object NAME to inotify instance FD. Private Extern inotify_add_watch(__fd As Integer, name As String, __mask As Integer) As Integer ' int inotify_rm_watch (int __fd, int __wd) ' Remove the watch specified by WD from the inotify instance FD. Private Extern inotify_rm_watch(__fd As Integer, __wd As Integer) As Integer ' int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout) ' Poll the file descriptors described by the NFDS structures starting at FDS. Private Extern poll(__fds As Pollfd, __nfds As Long, __timeout As Integer) As Integer ' ssize_t read (int __fd, void *__buf, size_t __nbytes) ' Read NBYTES into BUF from FD. Private Extern read_C(__fd As Integer, __buf As Pointer, __nbytes As Long) As Long Exec "read" ' int close (int __fd) ' Close the file descriptor FD. Private Extern close_C(__fd As Integer) As Integer Exec "close" Public Sub Main() Dim percorso_file As String Dim fd, wa As Integer Dim buf, p As Pointer Dim letti As Long Dim evento As New Inotify_event Dim pl As New Pollfd ' == Poniamo sotto osservazione la Cartella "/tmp", qualora venga creato o venga distrutto un file == percorso_file = "/tmp" fd = inotify_init() If fd = -1 Then Error.Raise("Impossibile inizializare 'inotify' !") wa = inotify_add_watch(fd, percorso_file, IN_ALL_EVENTS) If wa = -1 Then Error.Raise("Errore alla funzione esterna 'inotify_add_watch()' !") Print "Cartella '"; percorso_file; "' ...sotto osservazione !\n" buf = Alloc(CInt(BUFFER)) While bo = False pl.fd = fd pl.events = POLLIN letti = poll(pl, 1, 100) Select Case letti Case -1 Error.Raise("Errore alla funzione esterna 'poll()' !") Case 1 letti = read_C(fd, buf, BUFFER) If letti = -1 Then Error.Raise("Errore alla funzione esterna 'read_C()' !") End Select p = buf While p < buf + CInt(letti) evento = p If evento.mask And IN_CREATE Then Print "Creato il nuevo file: "; String@(evento.name.Data) If evento.mask And IN_DELETE Then Print "Eliminato il file: "; String@(evento.name.Data) If evento.mask And IN_MOVED_FROM Then Print "Spostato nel cestino il file: "; String@(evento.name.Data) p += 16 + evento.lenI Wend Wait 0.1 Wend ' Libera memoria in chiusura: Free(buf) inotify_rm_watch(fd, wa) close_C(fd) Quit End Public Sub Application_Read() ' Se si pone il puntatore del mouse nello spazio al di sotto della console e si preme il tasto "Invio" della tastiera, allora il programma va in chiusura... bo = True End