最近做一个数据迁移,数据存放在美国的一个FTP上,数据量在300G左右,文件在20万左右,需要下载到北京,使用FTP软件下载用户了一个星期才完成。因此想到用多线程来操作测试一下。思路如下:
- 先用主线程统计出FTP上所有的文件夹,并将文件夹路径存放到一个list中。
- 启动多个线程,读取list内容,分别登录FTP并下载。
看service 类:
package com.lenovo.plm.dms.ftp;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.SocketException;
import java.util.Iterator;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
public class Service {
private Iterator<String> ite;
Object lock;
public Service(Iterator<String> ite,Object lock){
this.ite = ite;
this.lock = lock;
}
public void execute() throws SocketException, IOException{
FTPClient ftp = new FTPClient();
ftp.connect("10.120.24.111", 21);
ftp.login("admin","admin");
if(!FTPReply.isPositiveCompletion(ftp.getReplyCode())){
ftp.disconnect();
return;
}
while(true){
String item = null;
synchronized(lock){
if(ite.hasNext()){
item = ite.next();
}else{
ftp.logout();
return;
}
}
if(item == null){
ftp.logout();
return;
}
System.out.println(Thread.currentThread().getName() + ":"+item);
downloadFile(ftp,item);
}
}
private void downloadFile(FTPClient ftp,String path){
try {
ftp.changeWorkingDirectory(path);
FTPFile[] files = ftp.listFiles();
for(FTPFile file:files){
if(file.getType() == 0){
File temp = new File("d:/temp/"+path);
if(!temp.exists()){
temp.mkdirs();
}
File localFile = new File(temp.getAbsolutePath()+file.getName());
System.out.println(Thread.currentThread().getName() + " download: " + localFile.getAbsolutePath() + localFile.getName());
OutputStream os = new FileOutputStream(localFile);
ftp.retrieveFile(file.getName(), os);
os.close();
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
这里是将list以迭代器的形式传入进行迭代。这个迭代器是多线程的共享资源,所以使用加锁来保证互斥访问。
线程类,直接掉用service即可。
package com.lenovo.plm.dms.ftp;
import java.io.IOException;
public class FTPThread extends Thread {
private Service service;
public FTPThread(Service service){
this.service = service;
}
@Override
public void run() {
// TODO Auto-generated method stub
try {
service.execute();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
执行类,用户统计FTP上所有的文件夹路径,另外启动多线程。
package com.lenovo.plm.dms.ftp;
import java.io.IOException;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
public class Main {
public static void main(String[] args) throws SocketException, IOException {
System.out.println("pulling dir information begin.");
List<String> list = new ArrayList<String>();
FTPClient ftp = new FTPClient();
ftp.connect("10.120.24.111", 21);
ftp.login("admin","admin");
if(!FTPReply.isPositiveCompletion(ftp.getReplyCode())){
ftp.disconnect();
return;
}
retriveDirs(ftp,list,"/lenovo");
ftp.logout();
System.out.println("pulling dir information end.");
Object lock = new Object();
Service service = new Service(list.iterator(),lock);
for(int i=0;i<5;i++){
FTPThread t = new FTPThread(service);
t.start();
}
}
public static void retriveDirs(FTPClient ftp,List<String> list,String remotePath) throws IOException{
ftp.changeWorkingDirectory(remotePath);
FTPFile[] fs = ftp.listFiles();
for(FTPFile file:fs){
if(file.getType() == 1){
list.add(remotePath + "/" + file.getName());
retriveDirs(ftp,list,remotePath + "/" + file.getName());
}
}
}
}