Search code examples
javaiofilesystemsdiffwatchservice

How to watch file for new content and retrieve that content


I have a file with name foo.txt. This file contains some text. I want to achieve following functionality:

  1. I launch program
  2. write something to the file (for example add one row: new string in foo.txt)
  3. I want to get ONLY NEW content of this file.

Can you clarify the best solution of this problem? Also I want resolve related issues: in case if I modify foo.txt I want to see diff.

The closest tool which I found in Java is WatchService but if I understood right this tool can only detect type of event happened on filesystem (create file or delete or modify).


Solution

  • Java Diff Utils is designed for that purpose.

    final List<String> originalFileContents = new ArrayList<String>();
    final String filePath = "C:/Users/BackSlash/Desktop/asd.txt";
    
    FileListener fileListener = new FileListener() {
    
        @Override
        public void fileDeleted(FileChangeEvent paramFileChangeEvent)
        throws Exception {
            // use this to handle file deletion event
    
        }
    
        @Override
        public void fileCreated(FileChangeEvent paramFileChangeEvent)
        throws Exception {
            // use this to handle file creation event
    
        }
    
        @Override
        public void fileChanged(FileChangeEvent paramFileChangeEvent)
        throws Exception {
            System.out.println("File Changed");
            //get new contents
            List<String> newFileContents = new ArrayList<String> ();
            getFileContents(filePath, newFileContents);
            //get the diff between the two files
            Patch patch = DiffUtils.diff(originalFileContents, newFileContents);
            //get single changes in a list
            List<Delta> deltas = patch.getDeltas();
            //print the changes
            for (Delta delta : deltas) {
                System.out.println(delta);
            }
        }
    };
    
    DefaultFileMonitor monitor = new DefaultFileMonitor(fileListener);
    try {
        FileObject fileObject = VFS.getManager().resolveFile(filePath);
        getFileContents(filePath, originalFileContents);
        monitor.addFile(fileObject);
        monitor.start();
    } catch (InterruptedException ex) {
        ex.printStackTrace();
    } catch (FileNotFoundException e) {
        //handle
        e.printStackTrace();
    } catch (IOException e) {
        //handle
        e.printStackTrace();
    }
    

    Where getFileContents is :

    void getFileContents(String path, List<String> contents) throws FileNotFoundException, IOException {
        contents.clear();
        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(path), "UTF-8"));
        String line = null;
        while ((line = reader.readLine()) != null) {
            contents.add(line);
        }
    }
    

    What I did:

    1. I loaded the original file contents in a List<String>.
    2. I used Apache Commons VFS to listen for file changes, using FileMonitor. You may ask, why? Because WatchService is only available starting from Java 7, while FileMonitor works with at least Java 5 (personal preference, if you prefer WatchService you can use it). note: Apache Commons VFS depends on Apache Commons Logging, you'll have to add both to your build path in order to make it work.
    3. I created a FileListener, then I implemented the fileChanged method.
    4. That method load new contents form the file, and uses Patch.diff to retrieve all differences, then prints them
    5. I created a DefaultFileMonitor, which basically listens for changes to a file, and I added my file to it.
    6. I started the monitor.

    After the monitor is started, it will begin listening for file changes.