notify icon indicating copy to clipboard operation
notify copied to clipboard

How to monitor content change in a file

Open lbhsot opened this issue 4 years ago • 3 comments

Hi, I'm new in rust and new in notify. I want to monitor content change in a file using code below. When I change my 123.sql the event will be always Create(Any).

Shouldn't it be Modify(DataChange)? I'm confused about this. How can I get the changed content correctly?

use crossbeam_channel::unbounded;
use notify::{RecommendedWatcher, RecursiveMode, Result, Watcher, EventKind, Config};
use std::time::Duration;
use notify::event::{ModifyKind, CreateKind, DataChange};

fn main() -> Result<()> {
    // Create a channel to receive the events.
    let (tx, rx) = unbounded();

    // Automatically select the best implementation for your platform.
    let mut watcher: RecommendedWatcher = Watcher::new(tx, Duration::from_secs(1))?;

    // Add a path to be watched. All files and directories at that path and
    // below will be monitored for changes.
    watcher.watch("/Users/samuel/123.sql", RecursiveMode::Recursive)?;

    loop {
        match rx.recv() {
           Ok(event) => {
               if event.is_ok() {
                   let real_event = event.unwrap();
                   match real_event.kind {
                       EventKind::Any => {
                           println!("any kind: {:?}", real_event.kind)
                       }
                       EventKind::Access(access_kind) => {
                           println!("access kind: {:?}", access_kind)
                       }
                       EventKind::Create(create_kind) => {
                           println!("create kind: {:?}", create_kind)
                       }
                       EventKind::Modify(modify_kind) => {
                           println!("modify kind: {:?}", modify_kind);
                       }
                       EventKind::Remove(remove_kind) => {
                           println!("remove kind: {:?}", remove_kind)
                       }
                       EventKind::Other => {
                           println!("other kind")
                       }
                       _ => {
                           println!("default kind")
                       }
                   }
               } else {

               }
           },
           Err(err) => println!("watch error: {:?}", err),
        };
    }

    Ok(())
}

lbhsot avatar Oct 12 '19 16:10 lbhsot

Having recently added a feature, here's what I think how things work today. Only ModifyKind::Any is emitted. DataChange does exists in code base but is never emitted. Also fyi, DataChange, (when used and emitted ) will tell you SOME data changed. It wont tell you WHAT changed. To know WHAT changed, you need to keep a cursor in the file and read delta from enf of the file.

sjoshid avatar Nov 03 '19 17:11 sjoshid

Sorry for not saying anything on this but I've never tried to monitor file content changes and would have to look into how this works..

0xpr03 avatar Nov 03 '19 19:11 0xpr03

To add to what others said:

The event classification describes 42 possible combinations, including 20 wildcards at varying levels (10 of each Any and Other). (I don't think there even exists an OS/driver/system that emits the full set, nevermind the existence of a notify implementation for such a system.) It's an aspirational classification to encode everything that could possibly be reported, currently and in the future, not a description of what events exist right now.

In general, events should be taken as "something changed," without delving deeper, and optionally "something was accessed/created/modified/removed." Looking at the exact event type is often unhelpful because it turns out that how systems actually work and how users perceive things can be wildly different and that's a major source of confusion. E.g. "saving a file" can be any of four or five different procedures depending on the application performing the save, and how even one of those procedures translates to filesystem events may vary between OSes.

There's no implementation currently that detects data change, mostly because that's expensive in most cases. The generic approach is to hash every file in the watch tree, and then read the file again either periodically (polling) or on another detection method (so as a second pass on top of the native events), hash the entire file again, and compare hashes. That's expensive both in time and space.

The reason why DataChange is in the classification is, beyond completeness, that there exists cases where this could be feasibly be done much more cheaply. For example, if the watch tree is inside some kind of version control (like git) or other system where files are already hashed (like btrfs), it could be possible to interrogate that system for either the hashes or even more directly, the diffs.

passcod avatar Nov 04 '19 01:11 passcod