使用WatchService类做文件监控总结


由于项目中要求做一个数据交互功能,大概就是为外系统将一些数据导入到本系统,数据中涉及到大量图片,以及文档,或其他资料,大小大概50-200M左右,因此决定使用ftp进行交互。

首先,提供外系统ftp账号,上传文件到文件服务器。

然后,本系统监控文件服务器相应文件夹。

本人在项目中使用的是WatchService类。

1、项目初始化后,开启一个线程做文件监控服务(此处建议是重新开启一个线程,避免影响项目其他功能)。

package com.*.*.modules.*.listener;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

import com.*.*.modules.*.service.FileWatcherService;
@Component("ContextEventHandler") 
public class ContextEventHandler implements ApplicationListener<ContextRefreshedEvent > {
	private static final Logger logger = Logger.getLogger(ContextEventHandler.class);
	@Resource
	private FileWatcherService fileWatcherService;
	@Override
	public void onApplicationEvent(ContextRefreshedEvent event) {
		if(event.getApplicationContext().getParent() == null){//root application context 没有parent,他就是老大.  
            //需要执行的逻辑代码,当spring容器初始化完成后就会执行该方法。 
			logger.info("-------------开启一个线程进行FTP文件监控服务-------------");
			new Thread(new Runnable() {	
				@Override
				public void run() {
					try {
						fileWatcherService.handleEvents();
					} catch (Exception e) {
						logger.error("-------------文件监控服务开启失败-------------", e);
					}
					
				}
			}).start();
        } 
	} 
}
2、

package com.*.*.modules.*.service;

import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
import static java.nio.file.StandardWatchEventKinds.OVERFLOW;

import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.ArrayList;
import java.util.List;


import javax.annotation.Resource;


import org.apache.log4j.Logger;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * **数据交互处理service
 * @author wuyp
 * @date 2017/11/25
 */
@Service("FileWatcherService")
public class FileWatcherService {
	@Resource
	...
	@Resource
	private ThreadPoolTaskExecutor executor;
	
	private final String uploadDir = Global.getConfig("uploadDir"); // 上传文件夹
	private final String backupDir = Global.getConfig("backupDir"); // 备份文件夹
	private final String unzipDir = Global.getConfig("unzipDir"); // 解压文件夹
	
	private WatchService watcher;  
	private static final Logger logger = Logger.getLogger(FileWatcherService.class);
	
    public FileWatcherService()throws IOException{ 
    	Path myDir = Paths.get(uploadDir);
    	logger.info("监控文件夹为"+uploadDir);
    	watcher = myDir.getFileSystem().newWatchService(); 
    	myDir.register(watcher, ENTRY_CREATE,ENTRY_DELETE);  //ENTRY_MODIFY
    }  
    
      public void handleEvents() throws Exception{ 
        while(true){  
        WatchKey key = watcher.take();
			for(WatchEvent<?> event : key.pollEvents()){  
				WatchEvent.Kind kind = event.kind();  
	            if(kind == OVERFLOW){//事件可能lost or discarded  
	                continue;  
	            }  
	            WatchEvent<Path> e = (WatchEvent<Path>)event;  
	            /* Path fileName = e.context(); 
	             File file = fileName.toFile();*/
	            String filePath = uploadDir+e.context();
	            logger.info("文件变动类型:"+kind.name()+",文件及路径:"+filePath);
	            if (kind == ENTRY_CREATE) {
	            	// 判断文件是否创建成功
	            	boolean fileIsCreateSuccess = fileIsCreateSuccess(filePath);
	            	if (fileIsCreateSuccess) {
	            		File file = new File(filePath);
	            		FileHandlingTask fileHandlingTask = new FileHandlingTask(file);
	            		executor.execute(fileHandlingTask);// 此处对文件进行处理
				}
	 		  }
            }  
            if(!key.reset()){  
                break;  
            }  
		} 
    }
}

大致的代码,就如上所示了。下面说下在开发过程中遇到的几个问题

1、在项目初始化时候启动监控服务

     由于项目是单体架构,初始化时候需要去完成一些其他功能,开始时候没有另起一个线程,直接在 WebContextListener里里监控,结果项目跑不动了,因为监控里是while(true),导致后续的初始化执行不了,因此需要另外开启一个线程。

2、ftp上传文件后,WatchService能立即监控到,但是此时文件不一定上传成功,立即对文件处理,造成很多错误

     开始,一直以为是文件夹权限,文件权限,或者ftp账号权限,最后赋予777权限都不行,最后证明统统都不是。

    原因是上传文件并没有完全成功就立即被监控到,立即对文件进行复制、解压处理。后来是在操作前睡眠10s,最终  还是偶尔有问题,因为大文件上传并不是10s就够,因此需要判断文件上传成功(http://blog.csdn.net/w20228396/article/details/78646336)

猜你喜欢

转载自blog.csdn.net/w20228396/article/details/78646687