2

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

gstackoverflow
  • 36,709
  • 117
  • 359
  • 710
  • [Java Diff Utils](https://code.google.com/p/java-diff-utils/) might help – BackSlash Jun 19 '14 at 07:59
  • Check here http://stackoverflow.com/questions/19480813/java-7-watchservice-get-file-change-offset – mkrakhin Jun 19 '14 at 08:04
  • It's impossible to get the difference only using this single file,unless you can make sure each modification is an appendant. – BlackJoker Jun 19 '14 at 08:04
  • @J.Rush It's possible, Java Diff Utils actually does it. It bases file comparison on contents saved in different lists. Actually you can save the original file in a list and load it in another list whenever it's edited, then compare the two lists to see the differences. – BackSlash Jun 19 '14 at 08:06
  • @BackSlash,i think the lists you mentioned must be stored in other files,am i right? – BlackJoker Jun 19 '14 at 08:12
  • @J.Rush No, I wasn't clear. Let's say we have `myFile.txt`. When the program is launched, it will retrieve the contents of `myFile.txt` and store them in a `List`, let's call it `originalFileContents`. Every time `myFile.txt` gets modified, we load the file into another list, `newFileContents`. At this point we can do `diff(originalFileContents, newFileContents)` to find differences between the original file contents and the new ones. – BackSlash Jun 19 '14 at 08:16
  • @BackSlash looks like very good library. I think if you add code example in answer it would a superb topic for stackoverflow – gstackoverflow Jun 19 '14 at 08:21
  • @gstackoverflow Ok, I'm creating an example – BackSlash Jun 19 '14 at 08:39

1 Answers1

2

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.

BackSlash
  • 21,927
  • 22
  • 96
  • 136
  • you forgot to add realization of method **getFileContents** – gstackoverflow Jun 19 '14 at 09:35
  • @gstackoverflow Added it. I'm not very familiar with `WatchService`, a good starting point is the [Oracle Tutorials](http://docs.oracle.com/javase/tutorial/essential/io/notification.html) page about it. – BackSlash Jun 19 '14 at 10:04
  • strange behaviour if at the moment of handling event was happened new event – gstackoverflow Jun 19 '14 at 10:27
  • if you will have more information - please add it here in future – gstackoverflow Jun 19 '14 at 11:53
  • Do you know if there is a way to get the diff without having to store old contents and new contents in memory and manually (or with some library) calculating the diff? In case the file is large, this looks not very efficient. I wonder if filesystems have some push API which can push only diffs, and if so, if there is a Java library on top of that. – G. Urikh Dec 27 '20 at 11:38
  • 1
    @G.Urikh Not that I'm aware of. There surely are tools for diffing files which are memory efficient, but I don't think file systems expose an API for that purpose, although it's something they may use internally to efficiently store file changes. Likely you will have to write your own code to read small chunks from both files and compute the diff without being too heavy on memory (if you are lucky someone already did it and shared the code). – BackSlash Dec 27 '20 at 14:13