在公司因为需要做一个从FTP服务器上下载文件的小程序,简单描述一下,后面直接上代码。
当应用程序被调用时,会从配置文件中读取配置信息,根据配置信息连接远程的FTP服务器,根据服务器上的文件的名称、文件的大小去数据库中查询数据。
数据库中存在: 不进行任何操作。
数据库中不存在:下载文件至本地,并且更新数据库信息。
具体实现代码:
public class FtpDownLoad {
//从配置文件中获取配置信息
private String name; //FTP名称
private String url; //FTP服务器ip地址
private int port; //FTP服务器端口
private String username;//FTP登录账号
private String password;//FTP登录密码
private String rootPath;//FTP服务器上的相对路径
private String localpath;//下载后保存到本地的路径
private FTPClient ftpClient; //连接FTP服务器的客户端
//循环读取配置文件进行FTP采集信息
public void execute(){
Element element = ServiceConfigHelper.getServiceConfig("ftpConfig.xml");
String elementValue = ServiceConfigHelper.getElementValue(element, "link-count");
int count = Integer.parseInt(elementValue);
for (int i = 0; i < count; i++) {
Map ftpMap = ServiceConfigHelper.getNextNodes("ftpConfig.xml", "ftp-"+(i+1));
name = ftpMap.get("name");
url = ftpMap.get("ip");
port = Integer.parseInt(ftpMap.get("port"));
username = ftpMap.get("username");
password = ftpMap.get("password");
rootPath = ftpMap.get("remotepath");
localpath = ftpMap.get("localpath");
//设置模式,默认为主动模式,如果配置文件中配置了被动模式设置,则为被动模式
int type = ftpMap.get("passivemode")!=null?2:1;
//循环调用采集的方法
this.connectFTP(type);
//下载文件
this.ftpDownFiles(rootPath, localpath);
}
//采集完毕后,关闭资源
if (ftpClient!=null && ftpClient.isConnected()) {
try {
ftpClient.logout();
ftpClient.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* @Title: connectFTP
* @Description: 连接FTP远程服务器
* @return boolean 是否连接成功
*/
public boolean connectFTP(int type){
boolean flag = false;
ftpClient = new FTPClient();
int reply = 0;
try {
ftpClient.connect(url, port);
//解决中文乱码问题
ftpClient.setControlEncoding("GBK");
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
//如果采用默认端口,可以使用ftp.connect(url)的方式直接连接FTP服务器
ftpClient.login(username, password);//登录
reply = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftpClient.disconnect();
return flag;
}
//默认为主动模式
if (type==1) {
ftpClient.enterLocalActiveMode();//主动模式
}else if(type==2){
ftpClient.enterLocalPassiveMode(); //被动模式
}
System.out.println("连接【"+this.name+"】FTP服务器成功!!");
flag = true;
return flag;
} catch (SocketException e) {
System.out.println("连接FTP服务器失败!!");
e.printStackTrace();
} catch (IOException e) {
System.out.println("连接FTP服务器失败!!");
e.printStackTrace();
}
return flag;
}
/**
*
* @Title: ftpDownFiles
* @Description: 从FTP服务器指定目录下载文件
* @throws
*/
public void ftpDownFiles(String ftpfilepath, String localpath) {
if (ftpfilepath.length()>1) {
if (!ftpfilepath.startsWith("/") || !ftpfilepath.endsWith("/")) {
System.err.println("FTP服务器路径名称错误---"+ftpfilepath);
return;
}
}
try {
FTPFile[] ff = ftpClient.listFiles(ftpfilepath);
if (ff != null) {
//循环遍历当前目录下的每一个文件
for (FTPFile file : ff) {
//防止进入死循环
if (file.getName().equals(".") || file.getName().equals("..")) {
continue;
}
// 根据ftp文件生成相应本地文件
String localfilepath = localpath + file.getName();
File localFile = new File(localfilepath);
// 获取ftp文件最后修改时间
Date fflastModifiedDate = file.getTimestamp().getTime();
//获取ftp文件的大小
long size = file.getSize();
//System.out.println("\t\t"+(file.isDirectory()?"目录":"文件")+"名称为:"+file.getName());
// 如果是目录
if (file.isDirectory()) {
// 如果本地文件夹不存在就创建
localFile.mkdir();
// 转到ftp文件夹目录下
String ftpfp = ftpfilepath + file.getName() + "/";
// 转到本地文件夹目录下
String localfp = localfilepath+ "/";//+"/"
// 递归调用
//System.out.println("\t\t切换目录为:"+ftpClient.printWorkingDirectory());
this.ftpDownFiles(ftpfp, localfp);
}
else if (file.isFile()) {
// 如果是文件
File lFile = new File(localpath);
lFile.mkdir();
// 如果文件所在的文件夹不存在就创建
if (!lFile.exists()) {
return;
}
//FTP服务器上的文件全路径名称
String filepath = ftpfilepath + file.getName();
//if (file.getSize() != localFile.length() || result < 0) {
//判断文件是否需要下载
if (DBHelper.isDownLoad(filepath,size)) {
// 目标ftp文件下载路径
FileOutputStream fos = new FileOutputStream(
localFile);
boolean boo = false;
try {
/**
*从服务器检索一个命名文件并将其写入给定的OutputStream。
*此方法不会关闭给定的OutputStream。
*如果当前文件类型是ASCII,则文件中的行分隔符将转换为本地表示形式。
* */
// 从FTP服务器上下载一个文件
boo = ftpClient.retrieveFile(new String(filepath.getBytes("GBK"),"ISO-8859-1"), fos);
if (boo) {
System.out.println("\t文件【"+localFile.getAbsolutePath()+"】下载成功" );
//保存至数据库
SimpleDateFormat sFormat = new SimpleDateFormat("YYYY-MM-dd hh:mm:ss");
String time = sFormat.format(fflastModifiedDate);
DBHelper.saveInfo(filepath,size,time);
}else {
System.err.println("\t文件【"+localFile.getAbsolutePath()+"】下载失败" );
}
} catch (Exception e) {
boo = false;
e.printStackTrace();
}
// 将缓冲区中的数据全部写出
fos.flush();
// 关闭流
fos.close();
}
}
}
}else{
System.out.println("\t根目录下没有文件");
}
} catch (Exception e) {
e.printStackTrace();
}
}
//进行测试
public static void main(String[] args) throws IOException {
FtpDownLoad ftpDownload = new FtpDownLoad();
//连接FTP服务器,采集信息
ftpDownload.execute();
}
}
代码注释已经比较详细,但是只支持中文文件名下载,但是中文目录下的文件并没有遍历到,不知道什么原因,希望懂的可以帮忙解决一下。
注释:
1. 从配置文件中获取ftp的连接信息(地址,用户名,密码,主被动连接等)
2. 从配置文件中获取数据库的连接信息
3. 动态生成本地文件