本文轉自: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接口沒有方法,只是一個接口標識
- package cn.std.run.monitor;
- public interface Monitor{
- }
- package cn.std.run.monitor;
- public interface Monitor{
- }
2,FileMonitor,這是一個文件監控的接口,繼承Monitor,定義了文件監控的幾個方法,所有有關文件監控的實現類,都必須實現此接口
- 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);
- }
- 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類,就搞定
- 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();
- }
- }
- }
- 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方法會被調用,參數是新增加的文件名
- 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();
- }
- }
- 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();
- }
- }
好了,運行起來看看結果:
另外,附上我自己封裝的一個用來保存數據的類,暫定義是Cache,因爲我開發這個實際上是準備用來做一個自己的緩存的功能的,完畢。