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
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