1 Overview
A recent company mission requires real-time monitoring of changes in the content of a file in a file system. Because the program itself is written in Java, Inotify-java (http://code.google.com/p/inotify-java/) is used. Inotify-java only encapsulates kernel calls related to INotify in Linux, so it is necessary to understand inotify before using Inotify-java.
INotify is a file system monitoring mechanism based on inode. From the 2.6.13-RC3 version is integrated into the Linux kernel as an alternative to the dnotify. Compared to Dnotify, INotify has the following major advantages in addition to being easier to use:
- INotify uses an asynchronous event notification mechanism.
- You can monitor any object in the file system (Dnotify can only monitor the directory). If inotify is monitoring a directory, inotify can notify the changed file name when a file in the directory changes (Dnotify can only report changes, and the application itself needs to determine which file has changed).
- For each monitored file, inotify does not need to maintain an open file descriptor, so it does not affect operations such as unmount, but instead gets a notification when the file system where the monitored file resides is unmount.
2 inotify
2.1 Interfaces
If C library supports inotify, then the C program directly include <sys/inotify.h>.
Initialized with an int inotify_init (void) system call. A return value of less than 0 indicates that the call failed; otherwise a inotify instance is created in the kernel and the corresponding file descriptor is returned. This file descriptor is used to read INotify events (INotify event), which can be read in either a blocking style, such as read, or non-blocking, such as Select,poll and Epoll (Java6 has already supported Epoll, Select is not supported for FileChannel, however.
Add monitoring (watch) via an int inotify_add_watch (int fd, const char *path, __U32 mask) system call. The parameter fd is the file descriptor returned by the Inotify_init call, the path to the Monitoring object (file, directory, etc.), and the parameter mask is the bitmask of the event type that is expected to be notified. INotify can monitor the following types of events: Opens, closes, reads, writes, creates, deletes, moves, metadata changes, and unmounts. You can add multiple monitors to a inotify instance. The system call returns a monitor descriptor (watch descriptor) in case of success, which is used to identify different monitors. The optional values for the mask parameter are as follows:
Event |
Description |
In_access |
File is read from. |
In_modify |
File was written to. |
In_attrib |
File ' s metadata (inode or xattr) was changed. |
In_close_write |
File was closed (and is open for writing). |
In_close_nowrite |
File was closed (and is not an open for writing). |
In_open |
File was opened. |
In_moved_from |
File is moved away from watch. |
In_moved_to |
File is moved to watch. |
In_delete |
File was deleted. |
In_delete_self |
The watch itself was deleted. |
In_close |
In_close_write | In_close_nowrite |
In_move |
In_moved_from | In_moved_to |
In_all_events |
Bitwise OR of all events. |
In_oneshot |
One shot support |
If you want to monitor read and modify events for/home/user1/data.txt files, you can use In_access and in_modify, for example:
C code
- int WD;
- WD = Inotify_add_watch (FD, "/home/user1/data.txt", In_access | In_modify);
If you want to monitor only the modification events of the/home/user1/data.txt file once, you can use In_modify and in_oneshot, for example:
C code
- int WD;
- WD = Inotify_add_watch (FD, "/home/user1/data.txt", In_modify | In_oneshot);
Remove monitoring via int inotify_rm_watch (int fd, int wd) system call. The parameter fd is the file descriptor returned by the Inotify_init call, and the parameter WD is the monitor descriptor to be removed. Returns 0 if the call succeeds, otherwise a negative value is returned.
Destroys the inotify instance through the int close (int fd) system call, along with any associated monitoring and pending events. The parameter fd is the file descriptor returned by the Inotify_init call.
2.2 Configuration
The inotify can be configured through PROCFS and Sysctl. The following three files are available in the/proc/sys/fs/inotify/directory:
- Max_queued_events the maximum number of queued events. If the number of queued events reaches this value, the new time is discarded and the In_q_overflow event is sent. The default value is 16,384.
- Max_user_instances the maximum number of inotify instances that can be created per user. The default value is 128.
- Max_user_watches the maximum number of monitors that each user can create. The default value is 8,192.
2.3 Notifications
The events for INotify are asynchronous and queued internally. However, the reading of the event must be done in a synchronous manner. If read, the method is blocked until an event arrives, and the event is read into all queued events at one time. The notification event for inotify is defined by the inotify_event structure, as follows:
C code
- struct Inotify_event {
- __S32 WD; / * Watch descriptor * /
- __u32 Mask; / * Watch mask * /
- __u32 cookies; / * Cookie to synchronize the events * /
- __u32 Len; /* Length (including nulls) of name */
- Char name[0]; / * stub for possible name * /
- };
Where WD is the monitor descriptor corresponding to the monitor descriptor returned when calling Inotify_add_watch (). If the application wants to know the corresponding file, then the application itself needs to establish the corresponding relationship between the monitoring descriptor and the file; mask is the bitmask of events; cookies are used to correlate two separate events (for example, In_moved_from and in_moved_to events) Len is the length of name, name is the name of the object in which the event occurred, and if the directory is monitored, name is the file name where the event occurred. If the file is monitored, then name is null.
If the directory or file being monitored is unmount uninstalled, then inotify will send In_unmount. Assuming that the monitoring object is a directory, if a file in the monitored directory is moved to a monitored directory, then inotify sends the In_moved_from event, and if a file outside the monitored directory is moved to the monitored directory, inotify sends in_moved_to If a file in the monitored Directory is renamed (that is, moved to the same directory), then inotify sends In_moved_from and in_moved_to two events, and the two events have the same cookie.
It is important to note that if you use VI to edit a monitored file, you will not get the In_modify event, but will get in_delete_self, In_move_self, and in_ignored three events. This is because VI is actually edited on a copy, and the original file is overwritten when it is saved. Receive the In_ignored event description The monitoring has been automatically removed from the INotify instance (because the monitoring object has been deleted, or the file system is unmount). Because the monitoring has been removed, the INotify instance will no longer send any events related to this file.
3 Inotify-java
Inotify-java is not complex, and each inotify instance creates two threads: Readerthread and Queuethread. Readerthread calls the native Read method in the loop to receive the event and puts the received event into Blockingqueue. Queuethread take event from Blockingqueue, callback Inotifyeventlistener.
Inotify-java is also relatively simple to use. You first need to instantiate the INotify object (called System.loadlibrary ("Inotify-java") in its constructor, and then register on the INotify object Inotifyeventlistener Finally, the Addwatch method of INotify object is added to monitor. The following is a sample code for a segment:
Java code
- Import Java.util.HashMap;
- Import Java.util.Map;
- Import Com.den_4.inotify_java. Constants;
- Import Com.den_4.inotify_java. Eventqueuefull;
- Import Com.den_4.inotify_java. Inotify;
- Import Com.den_4.inotify_java. Inotifyevent;
- Import Com.den_4.inotify_java. Inotifyeventlistener;
- Public class Test {
- //
- private Static final Map<integer, string> masks = new Hashmap<integer, string> ();
- Static {
- Masks.put (constants.in_access, "in_access");
- Masks.put (constants.in_modify, "in_modify");
- Masks.put (Constants.in_attrib, "In_attrib");
- Masks.put (Constants.in_close_write, "In_close_write");
- Masks.put (Constants.in_close_nowrite, "In_close_nowrite");
- Masks.put (Constants.in_open, "In_open");
- Masks.put (Constants.in_moved_from, "In_moved_from");
- Masks.put (constants.in_moved_to, "in_moved_to");
- Masks.put (Constants.in_create, "in_create");
- Masks.put (Constants.in_delete, "In_delete");
- Masks.put (constants.in_delete_self, "in_delete_self");
- Masks.put (constants.in_move_self, "in_move_self");
- Masks.put (Constants.in_unmount, "In_unmount");
- Masks.put (Constants.in_q_overflow, "In_q_overflow");
- Masks.put (constants.in_ignored, "in_ignored");
- Masks.put (Constants.in_onlydir, "In_onlydir");
- Masks.put (Constants.in_dont_follow, "In_dont_follow");
- Masks.put (Constants.in_mask_add, "In_mask_add");
- Masks.put (Constants.in_isdir, "In_isdir");
- Masks.put (Constants.in_oneshot, "In_oneshot");
- }
- public static void Main (String args[]) {
- try {
- Inotify i = new Inotify ();
- Inotifyeventlistener e = new Inotifyeventlistener () {
- public void filesystemeventoccurred (Inotifyevent e) {
- System.out.println ("INotify event, Mask:" + getmask (E.getmask ()) + ", Name:" + e.getname () + ", now:" + Sys Tem.currenttimemillis ());
- }
- public void Queuefull (Eventqueuefull e) {
- System.out.println ("inotify event queue:" + e.getsource () + "is full");
- }
- };
- I.addinotifyeventlistener (e);
- I.addwatch ("./test/", constants.in_modify);
- } catch (Throwable e) {
- E.printstacktrace ();
- }
- }
- public static String getmask (int mask) {
- StringBuilder sb = new StringBuilder ();
- For (Integer m:masks.keyset ()) {
- if ((Mask & M)! = 0) {
- if (sb.length () > 0) {
- Sb.append ("|");
- }
- Sb.append (Masks.get (m));
- }
- }
- return sb.tostring ();
- }
- }
Inotify-java Linux System monitoring file changes, real-time notification Java program