Java如何监控某个目录下文件的变化,如文件增加、删除、修改,也包括子文件夹中的文件,有人建议使用jni,由于要跨平台,最好是纯java的,谢谢。

解决方案 »

  1.   

    http://topic.csdn.net/t/20030708/09/2002243.html
      

  2.   

    提供个想法,也不知道算不算是最笨的。
    利用File的listFiles() ,lastModified() ,isDirectory() 等方法
    0.写个类用于记录目录结构
    1.循环遍历需要监视的文件夹,记录下整个目录结构
    2.隔个5秒,10秒的,再遍历一遍
    3.比较两次取得的目录结构,是否相同
      

  3.   

    那有个特大的文件夹
    效率是个问题
    java中该有个这样的封装类
      

  4.   

    修改文件夹是通过java吗?如果是的话就很简单了
    写事件类,写监听器,使用Proxy代理下就OK了!
    如果不是通过java的话那就是用jni吧,或者只能是 线程扫描了。
      

  5.   

    想到一个貌似简单的方法,不过是区别OS的,也就是你底层要设计得好。1.利用command列出文件夹结构(包括子文件夹), 例如: widnows用 dir /S; solaris用 ls -r(具体参数记不清了),保存文件
    2.隔段时间,再列一遍
    3.然后比较两个文件
      

  6.   

    我知道继续递归,但是文件的信息使用什么数据结构存储?我之前使用HashMap,创建两个HashMap分别为原来的文件信息:prevFiles和当前的文件信息:currentFiles,键值为<文件路径,最后修改时间>每次扫描前都执行,                prevFiles.clear();
    prevFiles.putAll(currentFiles);
    currentFiles.clear();这样当递归时currentFiles中数据存储的是子目录中的信息,而prevFiles中存的则是根目录下的信息
      

  7.   

    代码如下基类RunThread.java
    public abstract class RunThread implements Runnable
    {

        private int second;
        private String filePath;
        Thread runner;
    /**
     * @param second   时间间隔
     * @param filePath 文件路径
     */
    public RunThread(int second,String filePath)
        {
         this.second = second*1000;
         this.filePath = filePath;
        }
    public void onStart()
        {
         runner = new Thread(this);
         runner.start();
        }
    public void run() {
    // TODO Auto-generated method stub
    Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
    while(true)
    {
    try {
    watch(filePath);
    Thread.sleep(1000);
    } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }

    }
    public abstract void watch(String file);}子类 MonitorDir.javaimport java.io.File;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Vector;
    /**
     * 监控文件目录
     * @author han
     * @date 2009-10-10
     */
    public class MonitorDir  extends RunThread
    {
    public Map prevFiles = new HashMap();//存储原来文件路径和最后修改时间
    public Map currentFiles = new HashMap();//存储当前文件路径和最后修改时间
    public Map tmpCurrFiles = new HashMap();
    public Map tmpPrevFiles = new HashMap();
    public static Vector vList = new Vector();
    public Vector vtList = new Vector();

    /**
     * @param second  定时扫描间隔
     * @param filePath 目录路径
     */
    public MonitorDir(int second, String filePath) 
    {
    super(second, filePath);
    File dirFile = new File(filePath);
    if(dirFile.isDirectory())
    {
    System.out.println("start to watch " + dirFile.getAbsolutePath());
    }


    }

    /**
     * 获取文件的信息
     * @param dirPath
     */
    public void getFilesInfo(String dirPath)
    {
    File dirFile = new File(dirPath);

    prevFiles.clear();
    prevFiles.putAll(currentFiles);
    currentFiles.clear();

    File []fileList = dirFile.listFiles();
    for(int i = 0; i < fileList.length; i++)
    {
    File tmpFile = fileList[i];
    if(tmpFile.isFile())//文件
    {
    currentFiles.put(tmpFile.getAbsolutePath(), tmpFile.lastModified());

    }
    else//子目录则递归
    {
    String tmpPath = tmpFile.getAbsolutePath();
    getFilesInfo(tmpPath);
    } }

    }
    public void addFile(String file)
    {
    System.out.println(file+" is add");
    }
    public void changed(String file)
    {
    System.out.println(file+" is changed");
    }
    public void delete(String file)
    {
    System.out.println(file+" is delete");
    }

    /*
     * 监控
     */
    public void watch(String dirPath)
    {

    getFilesInfo(dirPath);
    Iterator currentIt =  currentFiles.keySet().iterator();
    while(currentIt.hasNext())
    {
    String filePath = (String)currentIt.next();
    Long currentModify = (Long) currentFiles.get(filePath);
    if(!prevFiles.containsKey(filePath))//假如原来的hashmap中不存在当前键,则为增加的
    {
    addFile(filePath);
    //if()
    }
    else if(prevFiles.containsKey(filePath))
    {
    Long prevModify = (Long)prevFiles.get(filePath);
    if(prevModify.compareTo(currentModify)!=0)//最后修改时间不同,则为改变的
    {
    changed(filePath);
    }
    }
    //System.out.println("当前------"+filePath+","+currentModify);
    }
    Iterator prevIt = prevFiles.keySet().iterator();
    while(prevIt.hasNext())
    {
    String prevFilePath = prevIt.next().toString();
    if(!currentFiles.containsKey(prevFilePath))//原来的键不在当前hashmap中,则为删除的
    {
    delete(prevFilePath);
    }
    //System.out.println("原来------"+prevFilePath+","+tmpPrevFiles.get(prevFilePath));
    }

    }

    public static void main(String args[])
    {
    MonitorDir md = new MonitorDir(5,"D:/data/");
    md.onStart();

    }

    }假如屏蔽递归那一句,能够监控根目录下文件的变化,使用递归时一直都在变化,是数据存储的问题,但是还找不到解决方法
      

  8.   


    import java.io.File;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Set;/**
     * <p>
     * Description:监控某个文件路径下的变化
     * </p>
     * @author imasmallbird
     * @version $Revision 1.1 $ 2009-10-10 下午01:14:26
     */
    public class DirMonitor implements Runnable {    /**
         * 监控的文件路径
         */
        private String dir;    /**
         * 扫描间隔时间以秒为单位
         */
        private int period;    /**
         * 原有文件信息
         */
        private Map < String, String > oldDirFileMap;    /**
         * 初始化相关数据
         */
        public DirMonitor(String dir, int period) {
            this.dir = dir;
            this.period = period;
            this.oldDirFileMap = new HashMap < String, String >();
        }    /**
         * 线程的执行。对于修改文件的情况,则视为删除与增加两个操作。
         */
        public void run() {        boolean isError = false;
            File file = new File(dir);
            // 初始化开始监控时的文件路径状态
            totalScan(file, oldDirFileMap);
            // 展示原有路径下的文件信息
            displayNowFile();
            while (!isError) {
                try {
                    Thread.sleep(period * 1000);
                    // 指定时间间间隔后扫描路径
                    Map < String, String > nowDirFileMap = new HashMap < String, String >();
                    totalScan(file, nowDirFileMap);
                    // 得到删除的文件及文件夹
                    getDeletedFile(nowDirFileMap);
                    // 得到新增的文件及文件夹
                    getAddedFile(nowDirFileMap);
                    // 注意:由于涉及到修改,所以一定要先检测删除的文件,然后再检测新增加的文件            } catch (InterruptedException e) {
                    System.out.println("对指定的文件路径进行监控时产生异常,异常信息为:" + e.getMessage());
                    isError = true;
                }
            }
        }    /**
         * 递归扫描整个路径
         * @param dir
         * @param ndir
         * @param dirFileMap 存放扫描结果
         */
        private void totalScan(File file, Map < String, String > dirFileMap) {        String[] fileList = file.list();
            // 判断是否为空目录
            if (null != fileList) {
                for (int i = 0; i < fileList.length; i++) {
                    String pname = file.getAbsolutePath() + "\\" + fileList[i];
                    File tempFile = new File(pname);
                    if (tempFile.isDirectory()) {
                        dirFileMap.put(pname, "文件夹:\t" + pname);
                        totalScan(tempFile, dirFileMap);
                    } else {
                        // 不相同的文件夹下,存放的文件可能名字相同,但是同一路径下的文件肯定不会相同,
                        // 所以采用全路径做为key值
                        dirFileMap.put(pname, "文件:\t" + pname);
                    }
                }
            }
        }    /**
         * 得到增加的文件及文件夹,并增加到已有的文件信息中
         */
        private void getAddedFile(Map < String, String > nowDirFileMap) {
            for (Iterator < String > iterator = nowDirFileMap.keySet().iterator(); iterator.hasNext();) {
                String key = iterator.next();
                if (null == oldDirFileMap.get(key)) {
                    oldDirFileMap.put(key, nowDirFileMap.get(key));
                    System.out.println("新增" + nowDirFileMap.get(key));
                }
            }
        }    /**
         * 得到删除的文件及文件夹,并删除已经不存在的文件信息
         */
        private void getDeletedFile(Map < String, String > nowDirFileMap) {
            for (Iterator < String > iterator = oldDirFileMap.keySet().iterator(); iterator.hasNext();) {
                String key = iterator.next();
                if (null == nowDirFileMap.get(key)) {
                    System.out.println("删除" + oldDirFileMap.get(key));
                    iterator.remove();
                    oldDirFileMap.remove(key);
                }
            }
        }    /**
         * 展示原有文件
         */
        private void displayNowFile() {
            System.out.println(dir + "路径原有文件目录如下:\n");
            Set set = oldDirFileMap.keySet();
            Iterator < String > iterator = set.iterator();
            while (iterator.hasNext()) {
                System.out.println(oldDirFileMap.get(iterator.next()));
            }
            System.out.println("========================");
        }    /**
         * just for test
         * @param args
         */
        public static void main(String[] args) {
            DirMonitor dirMonitor = new DirMonitor("D:\\temp", 5);
            dirMonitor.run();
        }
    }换成你自己的路径试试~~
    启动后直接在你的文件夹下操作然后查询控制台就可以了,包括,增加、删除、修改文件及文件夹
    其中修改,则视为删除后,重新增加,此外只是简单的实现,并没有对文件下有深层次的路径及大批文件进行测试,效率问题有待考证~其实在一楼给你的那个链接你按照那个思路改就行了
      

  9.   


    /**
     * 递归扫描整个路径
     * 
     * @param file
     *            要扫描的路径
     * @param dirFileMap
     *            存放扫描结果
     */
    private void totalScan(File file, Map<String, String> dirFileMap) { String[] fileList = file.list();
    // 判断是否为空目录
    if (null != fileList) {
    for (int i = 0; i < fileList.length; i++) {
    String pname = file.getAbsolutePath() + "\\" + fileList[i];
    File tempFile = new File(pname);
    if (tempFile.isDirectory()) {
    dirFileMap
    .put("文件夹:" + pname, tempFile.lastModified() + "");//修改了此处
    totalScan(tempFile, dirFileMap);
    } else {
    // 不相同的文件夹下,存放的文件可能名字相同,但是同一路径下的文件肯定不会相同,
    // 所以采用全路径做为key值
    dirFileMap.put("文件:" + pname, tempFile.lastModified() + "");//修改了此处
    }
    }
    }
    } /**
     * 得到增加的文件及文件夹,并增加到已有的文件信息中
     */
    private void getAddedFile(Map<String, String> nowDirFileMap) {
    for (Iterator<String> iterator = nowDirFileMap.keySet().iterator(); iterator
    .hasNext();) {
    String key = iterator.next();
    String oldValue = oldDirFileMap.get(key);
    String newValue = nowDirFileMap.get(key);
    if (null == oldValue) {
    oldDirFileMap.put(key, newValue);
    System.out.println("新增的" + key);
    }
    }
    } /**
     * 得到删除的文件及文件夹,并删除已经不存在的文件信息
     */
    private void getDeletedFile(Map<String, String> nowDirFileMap) {
    for (Iterator<String> iterator = oldDirFileMap.keySet().iterator(); iterator
    .hasNext();) {
    String key = iterator.next();
    String oldValue = oldDirFileMap.get(key);
    String newValue = nowDirFileMap.get(key);
    if (null == nowDirFileMap.get(key)) {
    System.out.println("删除的" + key);
    iterator.remove();
    oldDirFileMap.remove(key);
    } else if (!newValue.equals(oldValue)) {//修改了此处
    System.out.println("修改的" + key);
    oldDirFileMap.put(key, newValue);
    }
    }
    } /**
     * 展示原有文件
     */
    private void displayNowFile() {
    System.out.println(dir + "路径原有文件目录如下:\n");
    Set set = oldDirFileMap.keySet();
    Iterator<String> iterator = set.iterator();
    while (iterator.hasNext()) {
    System.out.println(iterator.next());//此处修改
    }
    System.out.println("========================");
    }对于上面问题进行了修改,可以监控修改的文件了,并且将对文件增加及修改的时间也做为value进行了存放
    有需要可以拿出来直接使用~
      

  10.   

    希望你能用下面方法做:
    1,判断是哪类操作系统(win,lin)
    2,如果是win用dir命令,如果lin用ls命令扫描指定目录的所有文件的修改时间
    3,将所有扫描文件信息保存到文件中去
    4,比较刚保存的文件与旧文件的不同就可以得到增加、删除、修改使用dir命令或者ls命令扫描是非常快的,费时的是比较哦
      

  11.   

    java遍历目录的速度是值得怀疑的,特别的网络盘的目录
      

  12.   

    我也这么想,也可以利用spring的task
      

  13.   

    也有道理,但是dir只能查看根目录下的文件和文件夹信息,当子目录发生变化时,它在根目录下的父目录的最后修改时间也会改变,但是我们只能知道到这层,具体是哪个子目录或者哪个文件发生变化我们就无法得知了。
      

  14.   

    要深入的去查找变化的子目录,之前就得全部遍历一次整个目录,存储里面所有文件的信息,这样等到变化时你才能知道具体是哪个变化了。你的意思是使用递归dir命令还是只在根目录层dir一次,然后保存?
      

  15.   

    好长的代码。不如用Jython了,反正也可移植。代码短多了。不说别的,就是os.path.walk就解决了递归子目录的问题。
      

  16.   

    欢迎各位java大侠、小虾加入QQ高级群:45271133  群满500人为止,热烈邀请大侠们加入指点~!
      

  17.   

    用dir /s 目录,
    例如: dir /s c:\
    这个命令是遍历C盘下所有文件夹和子文件夹,文件及子文件。
      

  18.   

    朋友可以试试看 commons-jci, 通过看它的api好像提供了相关的监听器,不过我没有仔细研究过。http://commons.apache.org/jci/commons-jci-fam/index.html
      

  19.   

    可以参考Jboss等应用服务器的热部署、Jakarta-Common-Configuration
      

  20.   

    #63楼的兄弟,如果你用个java遍历过你的C盘,你就不会说dir /s c:\ 这个命令遍历C盘慢,我相信你会说dir真TM快!
      

  21.   

    如果是BS系统,在客户端监控文件变化,可以采用Applet。
      

  22.   

    先用vc写一个java调用的dll
    内容:
    HANDLE   dwChangeHandles[2]; 
      dwChangeHandles[0]   =   FindFirstChangeNotification(     
              "C:\\WINDOWS",                                   //   directory   to   watch     
              FALSE,                                                   //   do   not   watch   the   subtree     
              FILE_NOTIFY_CHANGE_FILE_NAME);   //   watch   file   name   changes    dwChangeHandles[1]   =   FindFirstChangeNotification(     
              "C:\\",                                                 //   directory   to   watch     
              TRUE,                                                     //   watch   the   subtree     
              FILE_NOTIFY_CHANGE_DIR_NAME);     //   watch   dir.   name   changes  dwWaitStatus   =   WaitForMultipleObjects(2,   dwChangeHandles,     
                      FALSE,   INFINITE); 有文件修改就触发事件了。linux也应该有相应方法
      

  23.   

    通过OS的方式的话,应该会快很多吧,毕竟java要通过虚拟机
      

  24.   

    可以监控文件系统吧,有相关的API
      

  25.   

    新手上路;多多关照!
    个人思路:
        记得有种叫面向切面的编程思想!需要用到动态代理.log4j好像就用到它了!
        如果自己写增删改查可以参考下!
        如果不是自己写的,那我没有办法!
        学习中....
      

  26.   

    今天看了一下tomcat是怎么实现对web.xml修改之后会重新发布的,结果很失望,居然也是靠轮循的方式去比较文件的修改时间,有根线程每隔10s去跑一下。
      

  27.   

    用钩子做是比较好的一种方法
    我们现在做的CRM-呼叫中心就是这样子做的!~
      

  28.   

    用钩子做是比较好的一种方法
    我们现在做的CRM-呼叫中心就是这样子做的!~
      

  29.   

    学习,
    while (!isError) {
                try {
                    Thread.sleep(period * 1000);                // 指定时间间间隔后扫描路径
                    Map < String, String > nowDirFileMap = new HashMap < String, String >();
                    totalScan(file, nowDirFileMap);
                    // 得到删除的文件及文件夹
                    getDeletedFile(nowDirFileMap);
                    // 得到新增的文件及文件夹
                    getAddedFile(nowDirFileMap);
                    // 注意:由于涉及到修改,所以一定要先检测删除的文件,然后再检测新增加的文件            } catch (InterruptedException e) {
                    System.out.println("对指定的文件路径进行监控时产生异常,异常信息为:" + e.getMessage());
                    isError = true;
                }
            }
      

  30.   

    JNotify这应该是最有效率的开源侦听器,直接使用了操作系统的侦听能力,提供了多平台支持,甚至包括64位windows系统
      

  31.   

    JDK 7.0里提供了Watch Service API。详见http://www.developersky.net/thread-33-1-1.html