Java 文件監控,實時監控文件加載

本文轉自:http://blog.csdn.net/chichengit/article/details/8259837

前段時間設計一個文件自動加載系統模塊,功能就像是在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.  
[java] view plaincopy
  1. package cn.std.run.monitor;  
  2.   
  3. public interface Monitor{  
  4.   
  5. }  

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); 
[java] view plaincopy
  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. }  

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.      
[java] view plaincopy
  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. }  

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.     } 
[java] view plaincopy
  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. }  

好了,運行起來看看結果:


另外,附上我自己封裝的一個用來保存數據的類,暫定義是Cache,因爲我開發這個實際上是準備用來做一個自己的緩存的功能的,完畢。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章