简体   繁体   中英

detect file changes in Java without WatchService

I created a file checker that checks the file for changes every X sec. The problem is that if I check the file with WatchService it send modify event even if I do touch file . I can check the file.lenght , but what if my changes are not change the file size? is there any idea how can I detect the file changes?

This is my code( I'm using lastModified() method for a while )

class Checker implements Runnable {

static Logger log = Logger.getLogger(Monitor.class.getName());
private static final long DEFAULT_CHECK_INTERVAL = 5000; //5 sec
private static SimpleDateFormat dataFormat = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");    
private File file;
private long checkInterval;

public Checker(String path, long checkInterval) throws Exception {
    this.file = new File(path);
    this.checkInterval = checkInterval > 1000 ? checkInterval : DEFAULT_CHECK_INTERVAL;
}

private JSONObject loadConfig() {
    JSONObject conf = null;
    try(BufferedReader reader = new BufferedReader(new FileReader(this.file));) {

        StringBuilder bldr = new StringBuilder((int) this.file.length());
        String line = null;

        while((line = reader.readLine()) != null) {
            bldr.append(line);
        }

        conf = new JSONObject(bldr.toString());

            Thread.sleep(this.checkInterval);

    } catch (Exception e) {
        log.error(e);
    }
    return conf;
}   

@Override
public void run() {
    long modDate = 0;

    while (true) {
        long lastModified = this.file.lastModified();
        JSONObject conf = loadConfig();
        if (lastModified != modDate) {
            modDate = lastModified;
            log.warn("File changed at " + dataFormat.format(lastModified));
            log.info(conf.get("name") + ", " + conf.get("company"));                
        }
        log.info("no chenges");         

    }

}

public class Monitor {

    public static void main(String[] args) throws Exception {
        new Thread(new Checker("/home/arno/test/config.json", 2000)).start();      
    }
}

Maybe java NIO can help

BasicFileAttributes attr = Files.readAttributes(file, BasicFileAttributes.class); System.out.println("lastModifiedTime: " + attr.lastModifiedTime());

Maintain a duplicate of that file in some other directory.

For instance we have the file on the Desktop , maintain the copy of the file in C: and check for any difference.

File source = new File(""C://Desktop//filename.txt");
File dest = new File("C://temp//cache-filename.txt");
try {
    FileUtils.copyDirectory(source, dest);
} catch (IOException e) {
    e.printStackTrace();
}

And then maintain a timer, call your even everytime.

Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
  @Override
  public void run() {
  if(comapreTwoFiles("C://temp//cache-filename.txt", "C://Desktop//filename.txt")){
    System.out.println("File is changed");
    //change your cache file
    }
  }
}, 2*60*1000, 2*60*1000);
public boolean compareTwoFiles(String path1, String path2)
            throws IOException {

    File file1 = new File(path1);
    File file2 = new File(path2);

    BufferedReader br1 = new BufferedReader(new FileReader(file1));
    BufferedReader br2 = new BufferedReader(new FileReader(file2));

    String thisLine = null;
    String thatLine = null;

    List<String> list1 = new ArrayList<String>();
    List<String> list2 = new ArrayList<String>();

    while ((thisLine = br1.readLine()) != null) {
        list1.add(thisLine);
    }
    while ((thatLine = br2.readLine()) != null) {
        list2.add(thatLine);
    }

    br1.close();
    br2.close();

    return list1.equals(list2);
}

Checksum file using MD5

public class MD5 {
    public static String getMD5(String input) {
        try {
            byte[] thedigest = MessageDigest.getInstance("MD5").digest(input.getBytes("UTF-8"));
            BigInteger number = new BigInteger(1, thedigest);
            String hashtext = number.toString(16);
            // Now we need to zero pad it if you actually want the full 32 chars.
            while (hashtext.length() < 32) {
                hashtext = "0" + hashtext;
            }
            return hashtext;
        } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }
    public static boolean checksum(String filePath, String hashCode) {
        try {
            return getFileHash(filePath).equals(hashCode);
        } catch (Exception ex) {
            return false;
        }
    }
    public static String getFileHash(String filePath) {
        InputStream fis = null;
        try {
            fis = new FileInputStream(filePath);
            byte[] buffer = new byte[1024];
            MessageDigest complete = MessageDigest.getInstance("MD5");
            int numRead;
            do {
                numRead = fis.read(buffer);
                if (numRead > 0) {
                    complete.update(buffer, 0, numRead);
                }
            } while (numRead != -1);
            byte[] b = complete.digest();
            String result = "";
            for (int i = 0; i < b.length; i++) {
                result += Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1);
            }
            return result;
        } catch (IOException | NoSuchAlgorithmException ex) {
            Logger.getLogger(MD5.class.getName()).log(Level.SEVERE, null, ex);
            throw new RuntimeException(ex);
        } finally {
            try {
                if (fis != null) {
                    fis.close();
                }
            } catch (IOException ex) {
                Logger.getLogger(MD5.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
}

You can check the MD5 checksum instead the file size:

    import java.io.FileInputStream;
    import java.io.InputStream;
    import java.security.MessageDigest;

    public class Main {

        public static byte[] getMD5Checksum(String filename) throws Exception {
            InputStream fis = new FileInputStream(filename);
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] buffer = new byte[1024];
            int aux;
            do {
                aux = fis.read(buffer);
                if (aux > 0) {
                    md.update(buffer, 0, aux);
                }
            } while (aux != -1);
            fis.close();
            return md.digest();
        }

        private static String toHexString(byte[] bytes) {
            StringBuilder sb = new StringBuilder(bytes.length * 2);
            for (byte b : bytes)
                sb.append(String.format("%02x", b & 0xff));
            return sb.toString();
        }

        public static void main(String args[]) throws Exception {
            System.out.println(toHexString(getMD5Checksum("/Users/irineuantunes/Desktop/testFile.txt")));
        }

    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM