使用框架:SpringMVC
定时任务实现:继承org.springframework.scheduling.quartz.QuartzJobBean;
ftp环境搭建就不说了,在其他博客记录过,使用虚拟机中的CentOS搭建的FTP服务,创建FTP账号及对应目录,事先上传需要下载的图片地址。文件内容格式“图片ID||图片地址”。
方法一、最简单的实现方法就是先下载存储图片url地址的文件,然后读取文件遍历图片地址,调下载图片的方法将图片存储到本地,最后压缩下载的图片,完成后删除下载的图片,只保留压缩包。文件。
public class PictureTransferJob extends QuartzJobBean {
protected void executeInternal(JobExecutionContext arg0) throws JobExecutionException {
//实际的FTP配置是读取配置文件获取的
//FTP地址
String hostName ="172.16.20.229";
//FTP端口
int port = 21;
//FTP账号
String userName = "hf";
//ftp密码
String password = "123456";
//ftp文件存储目录
String ftpDowload = "/";
//文件本地存储路径
String path = this.getClass().getResource("/").getPath();
//图片地址文件存储目录
String addrPath = path.substring(1, path.indexOf("WEB-INF/classes"))+"picAddr";
//实际下载的图片存储目录
String picPath = path.substring(1, path.indexOf("WEB-INF/classes"))+"pic";
addrPath = addrPath.replace("%20"," ");
picPath = picPath.replace("%20"," ");
try {
//创建存储图片地址的文件
creatFile(addrPath);
//创建存储实际图片的文件
creatFile(picPath);
String oldAddrPath = addrPath;
String oldPicPath = picPath;
//创建FTP连接
FtpUtil2 ftpUtil2 = new FtpUtil2(hostName, port,userName, password, ftpDowload, true);
//遍历FTP目录下的文件
String[] files = ftpUtil2.ListAllFiles();
//本地数据库会有一个表记录下载过的文件,这里会查询数据库和ftp列出的文件名比较,如果已经下载过的文件就不会下载,避免重复下载。
//下面省略比较的过程,循环files数组,在本地创建文件
for(int i=0; i<files.length; i++) {
creatFile(addrPath + File.separator + fileName);
//ftpDowload是ftp服务器存储文件的地址,addrPath是本地存储文件的地址
//这里一个返回状态判断文件是否下载成功
boolean downloadInvestorFlag = ftpUtil2.downloadFile(ftpDowload, addrPath);
//文件下载成功后调读取文件的方法,将需要下载的图片地址存入容器
boolean entityState = setPictureDetail(addrPath, picPath, fileNameDate);
}
} catch (Exception e) {
e.printStackTrace();
//调记录错误日志的业务类用于发送下载文件出错的短信
}
}
//这里开始读图片地址
private boolean setPictureDetail(String addrPath,String picPath,String synDate) {
System.out.println("----------进入setPictureDetail方法-----------");
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(new FileInputStream(addrPath),"UTF-8"));
String row;
int count = 0;
//map中存储每行读取到的图片名称和URL地址
Map<String, String> addrMap=new HashMap<String, String>();
while ((row=br.readLine())!=null) {
try {
count++;
if (count==1)
{
continue;
}
String[] column = row.split("\\|\\|", -1);
addrMap.put(column[0].trim(), column[1].trim());
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println(new Date());
//这里调用压缩方法,压缩方法中会调用执行下载图片的方法
zipPic(picPath, synDate, addrMap);
System.out.println(new Date());
System.out.println("----------完成--------------");
return true;
} catch (Exception e) {
e.printStackTrace();
//调用记录错误日志的业务类
return false;
} finally {
try {
if (null != br)
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 根据url地址下载图片
* @throws IOException
*/
private boolean downPic(String picPath, List<Entry<String, String>> addrList, List<File> picList)throws IOException{
InputStream is = null;
FileOutputStream fos = null;
URL url = null;
String fileName = null;
String picAddr = null;
File pic = null;
try {
for(Map.Entry<String, String> addrEntry: addrList)
{
fileName = addrEntry.getKey();
picAddr = addrEntry.getValue();
//创建Url对象
url = new URL(picAddr);
is = url.openStream();
//URLConnection获取到的流通过InputStream直接写入字节数组会缺失数据,导致下载的图片不完整,使用org.apache.commons.io.IOUtils.toByteArray(urlconnection.openstream())可以解决
byte[] bytes = IOUtils.toByteArray(is);//new byte[is.available()];获取的字节
//流中数据读入字节数组,读入后,流中数据清空
pic = new File(picPath+fileName+".jpg");
fos = new FileOutputStream(pic);
fos.write(bytes);
//将下载的图片存入List,待图片全部下载完成后传入zip方法进行压缩
picList.add(pic);
fos.flush();
fos.close();
is.close();
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
if (null!=fos)
{
fos.close();
}
if (null!=is)
{
is.close();
}
}
}
//这里是压缩文件的伪代码
private void zipPic(picPath,synDate,addrMap){
//传入需要压缩的文件列表和压缩文件名
ZipUtil.zipByStream(picList,new File(picPath+synDate+".zip"));
}
/**
* 创建文件
* @param path
*/
private void creatFile(String path) {
File file = new File(path);
if(!file.exists()) {
file.mkdirs();
}
}
}
方法二、多线程下载、直接压缩流
方法一虽然实现了基本功能,但是由于需要下载的图片太多,以及压缩本地图片文件和删除图片也比较耗时,所以可以优化速度的地方有两个。一个就是提高下载图片的效率,一个就是提高压缩的效率。
提高下载效率的方法可以使用多线程下载,提高压缩效率的方法是可以不将图片保存到本地而直接压缩文件流。
多线程实现方式:首先我们保存了需要下载的文件的地址列表,我们要使用多线程下载就要保证不同线程下载的图片不会重复,因此需要一个标志来区分,这时就可以使用一个索引计数器,按每个线程下载一定量图片分割,从0开始,每隔比如400个图片就用一个线程下载,这样就可以确定需要的