Java 文件监控,实时监控文件加载

<script type="text/javascript"></script>

前段时间设计一个文件自动加载系统模块,功能就像是在Tomcat的webapps目录下发布war包那样,只要一有war包加载进来,tomcat立刻就会去解压这个war包,并把它挂载在tomcat上,供网络访问。

 

我这个程序的思路也正是这样,可以监控某一目录下的文件,包括文件的增加,删除,修改,正在加载,加载成功等事件,使用抽象类和接口方式来编写,要拓展此类,十分容易,当然这个也只是个人粗制滥造的一个小玩意,大有优化的空间。在JDK7.0中包含了文件监控的API,不过听说性能很不行,事件触发很不稳定,看来oracle收购了sun之后,Java前途一片渺茫啊....

 

先说说我设计的思路:启动一个不断循环的守护线程,不断检测某目录下的文件列表,并将这些文件名称和文件MD5校验码缓存起来,在下一个循环的时候直接从缓存中取出数据,进行对比,如果发现MD5校验不一样,说明文件被更新,还有文件增加,删除的事件,在代码中有相关的注释,下面开始贴代码

 

1,Monitor,这个是一个接口,开始时是设计用来做各种监控的,例如文件监控,内存监控,CPU监控,网络监控等,Monitor接口没有方法,只是一个接口标识

Java代码 复制代码  收藏代码
  1. package cn.std.run.monitor;   
  2.   
  3. public interface Monitor{   
  4.   
  5. }  
package cn.std.run.monitor;

public interface Monitor{

}

 

2,FileMonitor,这是一个文件监控的接口,继承Monitor,定义了文件监控的几个方法,所有有关文件监控的实现类,都必须实现此接口

Java代码 复制代码  收藏代码
  1. package cn.std.run.monitor;   
  2.   
  3.   
  4. public interface FileMonitor extends Monitor ,Runnable{   
  5.   
  6.     /** 文件删除 */  
  7.     void deleteAction(Object fileName);   
  8.     /** 文件增加 */  
  9.     void addAction(Object fileName);   
  10.     /** 文件更新 */  
  11.     void updateAction(Object fileName);   
  12.     /** 正在加载 */  
  13.     void isLoading(Object fileName);   
  14.     /** 加载成功 */  
  15.     void loadSuccess(Object fileName);   
  16. }  
package cn.std.run.monitor;


public interface FileMonitor extends Monitor ,Runnable{

	/** 文件删除 */
	void deleteAction(Object fileName);
	/** 文件增加 */
	void addAction(Object fileName);
	/** 文件更新 */
	void updateAction(Object fileName);
	/** 正在加载 */
	void isLoading(Object fileName);
	/** 加载成功 */
	void loadSuccess(Object fileName);
}

 

3,DiskFileMonitor,这是一个抽象类,实现FileMonitor接口,并对FileMonitor做了相关实现和拓展,提供给程序员后续开发的接口,程序员如果需要开发有关文件监控的相关功能,直接继承DiskFileMonitor类,就搞定

Java代码 复制代码  收藏代码
  1. package cn.std.run.monitor;   
  2.   
  3. import java.io.File;   
  4. import java.io.IOException;   
  5. import java.util.ArrayList;   
  6. import java.util.Enumeration;   
  7. import java.util.HashMap;   
  8. import java.util.List;   
  9. import java.util.Map;   
  10. import java.util.Vector;   
  11.   
  12. public abstract class DiskFileMonitor implements FileMonitor{   
  13.   
  14.     private final String ServiceFilesKey = "ServiceFiles";   
  15.     private final String ServiceFilesMapKey = "ServiceFilesMapKey";   
  16.     private String filePath = "./src/cn/std/pool/cache";   
  17.        
  18.     public DiskFileMonitor(String fpath) {   
  19.         try {   
  20.             filePath  = fpath;   
  21.             Vector<String> files = new Vector<String>();   
  22.             getFiles(files, fpath);   
  23.             CacheMgr.putCache(ServiceFilesKey,files);   
  24.             Map<String,String> hm = new HashMap<String,String>(files.size());   
  25.             for(String f:files){   
  26.                 String fp = fpath+"/"+f;   
  27.                 fp = fp.replaceAll("//""/");   
  28.                 try {   
  29.                     String hash = HashFile.getHash(fp, "MD5");   
  30.                     hm.put(f, hash);   
  31.                 } catch (Exception e) {   
  32.                     e.printStackTrace();   
  33.                 }   
  34.             }   
  35.             CacheMgr.putCache(ServiceFilesMapKey, hm);   
  36.             CacheMgr.lsCache();   
  37.             //Vector ve = (Vector)CacheMgr.getCache(ServiceFilesKey);   
  38.         } catch (IOException e) {   
  39.             e.printStackTrace();   
  40.         }   
  41.     }   
  42.        
  43.     /** 递归获取目录下的所有文件 */  
  44.     private static void getFiles(Vector<String> ret,String fpath) throws IOException {    
  45.         File dir = new File(fpath);    
  46.         File[] files = dir.listFiles();    
  47.            
  48.         if (files == null)    
  49.             return;    
  50.         for (int i = 0; i < files.length; i++) {    
  51.             if (files[i].isDirectory()) {    
  52.                 getFiles(ret,files[i].getAbsolutePath());    
  53.             } else {    
  54.                 String fileName = files[i].getName();   
  55.                 ret.addElement(fileName);   
  56.             }    
  57.         }    
  58.     }   
  59.        
  60.     @Override  
  61.     @SuppressWarnings("unchecked")   
  62.     public void run() {   
  63.         try {   
  64.             Vector<String> notLoadFiles = new Vector<String>();   
  65.             while(true){   
  66.                 Vector<String> diskfiles = new Vector<String>();   
  67.                 getFiles(diskfiles, filePath);//从磁盘中读出文件   
  68.                 //判断文件是否已经加载   
  69.                 Object obj = CacheMgr.getCache(ServiceFilesKey);   
  70.                 Vector<String> cachefiles = null;   
  71.                 if(obj instanceof Vector){   
  72.                     cachefiles = (Vector<String>)obj;   
  73.                 }   
  74.                 if(null != cachefiles){   
  75.                     int diskfilesSize = diskfiles.size();   
  76.                     int cachefilesSize = cachefiles.size();   
  77.                        
  78.                     //磁盘文件>缓存文件,说明磁盘中增加了文件   
  79.                     if(diskfilesSize > cachefilesSize){   
  80.                         Enumeration<String> diskEn = diskfiles.elements();   
  81.                         while(diskEn.hasMoreElements()){   
  82.                             Object diskElement = diskEn.nextElement();   
  83.                             if(cachefiles.contains(diskElement)){//如果缓存中已经包含了磁盘元素,进行下一个循环   
  84.                                 continue;   
  85.                             }else{   
  86.                                 notLoadFiles.addElement((String)diskElement);   
  87.                             }   
  88.                         }//end while    
  89.                     //磁盘中删除了文件   
  90.                     }else if(diskfilesSize < cachefilesSize){   
  91.                         Enumeration<String> cacheEn = cachefiles.elements();   
  92.                         while(cacheEn.hasMoreElements()){   
  93.                             Object cacheElement = cacheEn.nextElement();   
  94.                             if(diskfiles.contains(cacheElement)){//如果缓存中已经包含了磁盘元素,进行下一个循环   
  95.                                 continue;   
  96.                             }else{   
  97.                                 cachefiles.removeElement(cacheElement);   
  98.                             //  System.out.println(cacheElement+" 文件删除");   
  99.                                 deleteAction(cacheElement);   
  100.                                 HashMap<String,String> upmap = (HashMap<String,String>)CacheMgr.getCache(ServiceFilesMapKey);   
  101.                                 upmap.remove(cacheElement);   
  102.                             }   
  103.                         }//end while    
  104.                     //文件数量没有变化,分两种情况,1,删除N个文件同时又增加了N个文件。2,文件原封不动   
  105.                     }else {   
  106.                         Map<String,String> hm = (Map<String, String>) CacheMgr.getCache(ServiceFilesMapKey);   
  107.                         Enumeration<String> diskEn = diskfiles.elements();   
  108.                         Vector<Object> isIn = new Vector<Object>(diskfilesSize);   
  109.                         while(diskEn.hasMoreElements()){   
  110.                             Object diskElement = diskEn.nextElement();   
  111.                             String diskfilepath = filePath+"/"+diskElement;   
  112.                             diskfilepath = diskfilepath.replace("//""/");   
  113.                             String newhash = HashFile.getHash(diskfilepath, "MD5");   
  114.                             String mapHash = hm.get(diskElement);   
  115.                             if(null != mapHash){//如果不为空,说明有这个文件   
  116.                                 isIn.addElement(diskElement);   
  117.                                 if(mapHash.equals(newhash)){   
  118.                                     continue;   
  119.                                 }else{   
  120.                                     updateAction(diskElement);   
  121.                                     //更新文件hash   
  122.                                     HashMap<String,String> upmap = (HashMap<String,String>)CacheMgr.getCache(ServiceFilesMapKey);   
  123.                                     upmap.put(diskElement.toString(),newhash);   
  124.                                 }   
  125.                             }else{//如果为空,说明重命名了一个文件   
  126.                             //  deleteAction(diskElement);   
  127.                                 addAction(diskElement);   
  128.                                 hm.put(diskElement.toString(), newhash);   
  129.                                 cachefiles.addElement(diskElement.toString());   
  130.                                 isIn.addElement(diskElement);   
  131.                             }    
  132.                         }//end while   
  133.                            
  134.                         List<String> willRemove = new ArrayList<String>(hm.size());   
  135.                         //遍历已经存在的元素,找出被重命名的元素   
  136.                         for(Map.Entry<String, String> m:hm.entrySet()){   
  137.                             if(isIn.contains(m.getKey())){   
  138.                                 continue;   
  139.                             }else{   
  140.                                 willRemove.add(m.getKey());   
  141.                             }   
  142.                         }   
  143.                            
  144.                         for(String element:willRemove){   
  145.                             hm.remove(element);   
  146.                             cachefiles.removeElement(element);   
  147.                             deleteAction(element);   
  148.                         }   
  149.                     }   
  150.                        
  151.                     if(notLoadFiles.size() == 0){   
  152.                         //服务文件没有更新   
  153.                     }else{   
  154.                         //服务文件更新   
  155.                            
  156.                         Vector<String> loadedfiles = new Vector<String>();   
  157.                         //此处加载服务文件   
  158.                         for(String name:notLoadFiles){   
  159.                     //      System.out.println(name+" 未加载");   
  160.                             addAction(name);   
  161.                     //      System.out.println(name+" 正在加载..");   
  162.                             loadedfiles.addElement(name);   
  163.                             isLoading(name);   
  164.                     //      System.out.println(name+" 加载成功");   
  165.                             cachefiles.addElement(name);   
  166.                             HashMap<String, String> hm = (HashMap<String,String>)CacheMgr.getCache(ServiceFilesMapKey);   
  167.                             String path = filePath+"/"+name;   
  168.                             path = path.replace("//""/");   
  169.                             hm.put(name,HashFile.getHash(path, "MD5"));   
  170.                             loadSuccess(name);   
  171.                             CacheMgr.lsCache();   
  172.                         }   
  173.                         notLoadFiles.removeAll(loadedfiles);   
  174.                     }   
  175.                 }   
  176.                 Thread.sleep(500);   
  177.             }//end while(true)   
  178.         } catch (IOException e) {   
  179.             e.printStackTrace();   
  180.         } catch (InterruptedException e) {   
  181.             e.printStackTrace();   
  182.         } catch (Exception e) {   
  183.             e.printStackTrace();   
  184.         }   
  185.     }   
  186.        
  187. }  
package cn.std.run.monitor;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;

public abstract class DiskFileMonitor implements FileMonitor{

	private final String ServiceFilesKey = "ServiceFiles";
	private final String ServiceFilesMapKey = "ServiceFilesMapKey";
	private String filePath = "./src/cn/std/pool/cache";
	
	public DiskFileMonitor(String fpath) {
		try {
			filePath  = fpath;
			Vector<String> files = new Vector<String>();
			getFiles(files, fpath);
			CacheMgr.putCache(ServiceFilesKey,files);
			Map<String,String> hm = new HashMap<String,String>(files.size());
			for(String f:files){
				String fp = fpath+"/"+f;
				fp = fp.replaceAll("//", "/");
				try {
					String hash = HashFile.getHash(fp, "MD5");
					hm.put(f, hash);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			CacheMgr.putCache(ServiceFilesMapKey, hm);
			CacheMgr.lsCache();
			//Vector ve = (Vector)CacheMgr.getCache(ServiceFilesKey);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/** 递归获取目录下的所有文件 */
	private static void getFiles(Vector<String> ret,String fpath) throws IOException { 
        File dir = new File(fpath); 
        File[] files = dir.listFiles(); 
        
        if (files == null) 
            return; 
        for (int i = 0; i < files.length; i++) { 
            if (files[i].isDirectory()) { 
            	getFiles(ret,files[i].getAbsolutePath()); 
            } else { 
                String fileName = files[i].getName();
                ret.addElement(fileName);
            } 
        } 
    }
	
	@Override
	@SuppressWarnings("unchecked")
	public void run() {
		try {
			Vector<String> notLoadFiles = new Vector<String>();
			while(true){
				Vector<String> diskfiles = new Vector<String>();
				getFiles(diskfiles, filePath);//从磁盘中读出文件
				//判断文件是否已经加载
				Object obj = CacheMgr.getCache(ServiceFilesKey);
				Vector<String> cachefiles = null;
				if(obj instanceof Vector){
					cachefiles = (Vector<String>)obj;
				}
				if(null != cachefiles){
					int diskfilesSize = diskfiles.size();
					int cachefilesSize = cachefiles.size();
					
					//磁盘文件>缓存文件,说明磁盘中增加了文件
					if(diskfilesSize > cachefilesSize){
						Enumeration<String> diskEn = diskfiles.elements();
						while(diskEn.hasMoreElements()){
							Object diskElement = diskEn.nextElement();
							if(cachefiles.contains(diskElement)){//如果缓存中已经包含了磁盘元素,进行下一个循环
								continue;
							}else{
								notLoadFiles.addElement((String)diskElement);
							}
						}//end while 
					//磁盘中删除了文件
					}else if(diskfilesSize < cachefilesSize){
						Enumeration<String> cacheEn = cachefiles.elements();
						while(cacheEn.hasMoreElements()){
							Object cacheElement = cacheEn.nextElement();
							if(diskfiles.contains(cacheElement)){//如果缓存中已经包含了磁盘元素,进行下一个循环
								continue;
							}else{
								cachefiles.removeElement(cacheElement);
							//	System.out.println(cacheElement+" 文件删除");
								deleteAction(cacheElement);
								HashMap<String,String> upmap = (HashMap<String,String>)CacheMgr.getCache(ServiceFilesMapKey);
								upmap.remove(cacheElement);
							}
						}//end while 
					//文件数量没有变化,分两种情况,1,删除N个文件同时又增加了N个文件。2,文件原封不动
					}else {
						Map<String,String> hm = (Map<String, String>) CacheMgr.getCache(ServiceFilesMapKey);
						Enumeration<String> diskEn = diskfiles.elements();
						Vector<Object> isIn = new Vector<Object>(diskfilesSize);
						while(diskEn.hasMoreElements()){
							Object diskElement = diskEn.nextElement();
							String diskfilepath = filePath+"/"+diskElement;
							diskfilepath = diskfilepath.replace("//", "/");
							String newhash = HashFile.getHash(diskfilepath, "MD5");
							String mapHash = hm.get(diskElement);
							if(null != mapHash){//如果不为空,说明有这个文件
								isIn.addElement(diskElement);
								if(mapHash.equals(newhash)){
									continue;
								}else{
									updateAction(diskElement);
									//更新文件hash
									HashMap<String,String> upmap = (HashMap<String,String>)CacheMgr.getCache(ServiceFilesMapKey);
									upmap.put(diskElement.toString(),newhash);
								}
							}else{//如果为空,说明重命名了一个文件
							//	deleteAction(diskElement);
								addAction(diskElement);
								hm.put(diskElement.toString(), newhash);
								cachefiles.addElement(diskElement.toString());
								isIn.addElement(diskElement);
							} 
						}//end while
						
						List<String> willRemove = new ArrayList<String>(hm.size());
						//遍历已经存在的元素,找出被重命名的元素
						for(Map.Entry<String, String> m:hm.entrySet()){
							if(isIn.contains(m.getKey())){
								continue;
							}else{
								willRemove.add(m.getKey());
							}
						}
						
						for(String element:willRemove){
							hm.remove(element);
							cachefiles.removeElement(element);
							deleteAction(element);
						}
					}
					
					if(notLoadFiles.size() == 0){
						//服务文件没有更新
					}else{
						//服务文件更新
						
						Vector<String> loadedfiles = new Vector<String>();
						//此处加载服务文件
						for(String name:notLoadFiles){
					//		System.out.println(name+" 未加载");
							addAction(name);
					//		System.out.println(name+" 正在加载..");
							loadedfiles.addElement(name);
							isLoading(name);
					//		System.out.println(name+" 加载成功");
							cachefiles.addElement(name);
							HashMap<String, String> hm = (HashMap<String,String>)CacheMgr.getCache(ServiceFilesMapKey);
							String path = filePath+"/"+name;
							path = path.replace("//", "/");
							hm.put(name,HashFile.getHash(path, "MD5"));
							loadSuccess(name);
							CacheMgr.lsCache();
						}
						notLoadFiles.removeAll(loadedfiles);
					}
				}
				Thread.sleep(500);
			}//end while(true)
		} catch (IOException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
}

 

4,MyDiskFileMonitor,这是一个测试类,程序启动之后直接监控指定目录,指定目录下如果有文件变化,MyDiskFileMonitor会马上得到调用,例如,如果增加文件,AddAction方法会被调用,参数是新增加的文件名

Java代码 复制代码  收藏代码
  1. package cn.std.run.monitor;   
  2.   
  3. public class MyDiskFileMonitor extends DiskFileMonitor{   
  4.   
  5.     public MyDiskFileMonitor(String fpath) {   
  6.         super(fpath);   
  7.     }   
  8.   
  9.     @Override  
  10.     public void deleteAction(Object fileName) {   
  11.         System.out.println(fileName +" 元素删除");   
  12.     }   
  13.   
  14.     @Override  
  15.     public void addAction(Object fileName) {   
  16.         System.out.println(fileName +" 新增元素");   
  17.            
  18.     }   
  19.   
  20.     @Override  
  21.     public void updateAction(Object fileName) {   
  22.         System.out.println(fileName +" 元素更新");   
  23.            
  24.     }   
  25.   
  26.   
  27.     @Override  
  28.     public void isLoading(Object fileName) {   
  29.         System.out.println(fileName +" 正在加载");   
  30.     }   
  31.   
  32.     @Override  
  33.     public void loadSuccess(Object fileName) {   
  34.         System.out.println(fileName +" 加载成功");   
  35.     }   
  36.        
  37.     public static void main(String[] args) {   
  38.         String filePath = "F:/monitor";   
  39.         MyDiskFileMonitor mo = new MyDiskFileMonitor(filePath);   
  40.         new Thread(mo).start();   
  41.     }   
  42. }  
package cn.std.run.monitor;

public class MyDiskFileMonitor extends DiskFileMonitor{

	public MyDiskFileMonitor(String fpath) {
		super(fpath);
	}

	@Override
	public void deleteAction(Object fileName) {
		System.out.println(fileName +" 元素删除");
	}

	@Override
	public void addAction(Object fileName) {
		System.out.println(fileName +" 新增元素");
		
	}

	@Override
	public void updateAction(Object fileName) {
		System.out.println(fileName +" 元素更新");
		
	}


	@Override
	public void isLoading(Object fileName) {
		System.out.println(fileName +" 正在加载");
	}

	@Override
	public void loadSuccess(Object fileName) {
		System.out.println(fileName +" 加载成功");
	}
	
	public static void main(String[] args) {
		String filePath = "F:/monitor";
		MyDiskFileMonitor mo = new MyDiskFileMonitor(filePath);
		new Thread(mo).start();
	}
}

 

好了,运行起来看看结果:


Java 文件监控,实时监控文件加载

另外,附上我自己封装的一个用来保存数据的类,暂定义是Cache,因为我开发这个实际上是准备用来做一个自己的缓存的功能的,完毕。本人欢迎骚扰,呵呵....另外,本人表示刚毕业不久,原谅我的菜,哈哈

你可能感兴趣的:(java)