FTP上传与下载
使用的commons-net-3.3.jar包
一、上传
1 package com.ftp;
2
3 import java.io.File;
4 import java.io.FileInputStream;
5 import java.io.IOException;
6 import java.io.InputStream;
7 import java.net.SocketException;
8
9 import org.apache.commons.net.ftp.FTPClient;
10
11 /**
12 * ftp 连接演示
13 * 上传文件的功能
14 * @author Administrator
15 */
16 public class FtpUploadDemo {
17 public static void main(String[] args) throws SocketException, IOException {
18 FTPClient ftpClient = new FTPClient();
19 //连接 IP,内部默认的 port 是 0
20 ftpClient.connect("192.168.1.102",21);
21 //登入用户和密码
22 boolean isSuccess = ftpClient.login("fang", "fang");
23 if(!isSuccess){
24 System.out.println("服务器连接失败");
25 return ;
26 }
27 // 转到指定上传目录
28 ftpClient.changeWorkingDirectory("img");
29 //设置每次读取文件流时缓存数组的大小
30 ftpClient.setBufferSize(1024);
31 //设置编码方式
32 ftpClient.setControlEncoding("UTF-8");
33 //传输方式改为二进制传输
34 ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
35 //每次数据连接之前,ftp client告诉ftp server开通一个端口来传输数据
36 //因为数据传输的端口会变动
37 ftpClient.enterLocalPassiveMode();
38 //remote: FTP 文件名 ,上传文件的流
39 InputStream in = new FileInputStream("D:\\info.sql");
40 String remote = "info";
41 //上传文件到FTP
42 ftpClient.storeFile(remote, in);
43 // 关闭输入流
44 in.close();
45 // 退出ftp
46 ftpClient.logout();
47 System.out.println("上传成功");
48 }
49 }
二、下载
1 package com.ftp;
2
3 import java.io.File;
4 import java.io.FileOutputStream;
5 import java.io.IOException;
6 import java.io.OutputStream;
7 import java.net.SocketException;
8 import java.nio.file.Files;
9
10 import org.apache.commons.net.ftp.FTPClient;
11 import org.apache.commons.net.ftp.FTPFile;
12
13 /**
14 * ftp 连接演示
15 * 下载文件夹中文件的功能
16 * @author Administrator
17 */
18 public class FtpDownloadDemo {
19 public static void main(String[] args) throws SocketException, IOException {
20 FTPClient ftpClient = new FTPClient();
21 //连接 IP,内部默认的 port 是 0
22 ftpClient.connect("192.168.1.102",21);
23 //登入用户和密码
24 boolean isSuccess = ftpClient.login("fang", "fang");
25 if(!isSuccess){
26 System.out.println("服务器连接失败");
27 return ;
28 }
29 //设置本地路径
30 String localPath = "D:\\img";
31 File lp = new File(localPath);
32 if(!lp.exists()){//文件夹不存在时创建文件夹
33 lp.mkdirs();
34 }
35
36 // 转到指定下载文件目录
37 ftpClient.changeWorkingDirectory("img");
38 //设置每次读取文件流时缓存数组的大小
39 ftpClient.setBufferSize(1024);
40 //设置编码方式
41 ftpClient.setControlEncoding("UTF-8");
42 //传输方式改为二进制传输
43 ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
44 //每次数据连接之前,ftp client告诉ftp server开通一个端口来传输数据
45 //因为数据传输的端口会变动
46 ftpClient.enterLocalPassiveMode();
47 //列出该文件夹下 img 的这一层的所有文件和文件夹
48 //也就是说里面包含了 img 文件夹下的 文件 和 文件夹(不包含该文件夹的文件)
49 FTPFile[] ftpFileList = ftpClient.listFiles();
50
51 for (FTPFile ftpFile : ftpFileList) {
52 /**
53 * 有一些FTP服务器软件在返回文件(夹)列表时,回吧本目录和上级目录也一并返回,
54 * 也就是linux目录当中的“.”和“..”,
55 * 那么就会死循环。简单的解决办法就是getName判断一下是不是“.”和“..”
56 * System.out.println(ftpFile.getName() +ftpFile.getSize());
57 * getName() 得到文件的名字 getSize() 得到文件的大小(文件夹为 0)
58 */
59 if(ftpFile.getName().equals(".") || ftpFile.getName().equals("..")){
60 System.out.println(ftpFile.isFile());
61 continue;
62 }
63 //本地路径下初始化文件
64 String localFilePath = localPath + File.separator + ftpFile.getName();
65 //下载到本地的输出流
66 OutputStream out = new FileOutputStream(localFilePath);
67 //下载文件
68 ftpClient.retrieveFile(ftpFile.getName(), out);
69 //关闭流
70 out.close();
71 }
72 //退出Ftp
73 ftpClient.logout();
74 System.out.println("下载完毕");
75 }
76
77 }
此时,发现 ftp 中 img 文件夹下的文件夹以文件的形式也下载在本地,如图:
因此,代码进行更改,实现 gg 文件夹下的文件也进行下载。(img 整个目录文件下载)。
package com.ftp;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.SocketException;
import java.nio.file.Files;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
/**
* ftp 连接演示
* 下载文件夹中文件的功能
* @author Administrator
*/
public class FtpDownloadDemo {
public static void main(String[] args) throws Exception {
FTPClient ftpClient = new FTPClient();
//连接 IP,内部默认的 port 是 0
ftpClient.connect("192.168.1.102",21);
//登入用户和密码
boolean isSuccess = ftpClient.login("fang", "fang");
if(!isSuccess){
System.out.println("服务器连接失败");
return ;
}
// 转到指定下载文件目录
ftpClient.changeWorkingDirectory("img");
//设置每次读取文件流时缓存数组的大小
ftpClient.setBufferSize(1024);
//设置编码方式
ftpClient.setControlEncoding("UTF-8");
//传输方式改为二进制传输
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
//每次数据连接之前,ftp client告诉ftp server开通一个端口来传输数据
//因为数据传输的端口会变动
ftpClient.enterLocalPassiveMode();
//列出该文件夹下 img 的这一层的所有文件和文件夹
//也就是说里面包含了 img 文件夹下的 文件 和 文件夹(不包含该文件夹的文件)
FTPFile[] ftpFileList = ftpClient.listFiles();
//设置本地文件夹路径
String localPath = "D:\\img";
download(ftpFileList,ftpClient,localPath);
//退出Ftp
ftpClient.logout();
System.out.println("下载完毕");
}
public static void download(FTPFile[] ftpFileList,FTPClient ftpClient,String localPath) throws Exception{
File lp = new File(localPath);
if(!lp.exists()){//文件夹不存在时创建文件夹
lp.mkdirs();
}
for (FTPFile ftpFile : ftpFileList) {
if(ftpFile.getName().equals(".") || ftpFile.getName().equals("..")){
System.out.println(ftpFile.isFile());
continue;
}
//判断是否为文件夹
if(ftpFile.isDirectory()){
//ftp 下载的文件目录 例如 img 下的 gg
ftpClient.changeWorkingDirectory(ftpFile.getName());
ftpFileList = ftpClient.listFiles();
download(ftpFileList,ftpClient,localPath +File.separator + ftpFile.getName());
continue;
}
//本地路径下初始化文件
String localFilePath = localPath + File.separator + ftpFile.getName();
//下载到本地的输出流
OutputStream out = new FileOutputStream(localFilePath);
//下载文件
ftpClient.retrieveFile(ftpFile.getName(), out);
//关闭流
out.close();
}
}
}
package com.ftp; import java.io.File; //由于上述程序获得gg的 ftpFileList = ftpClient.listFiles(); //产生循环无数个 gg 文件夹 windows 电脑无法删除 //故写该程序进行循环删除 public class DeleteFile { public static void main(String[] args) { del("D:\\img"); } public static void del(String path){ File file = new File(path); File [] files = file.listFiles(); if(files.length == 0){ return; } path = path + File.separator + files[0].getName(); del(path); files[0].delete(); } }
小结:上传下载过程中的坑点
A)主动被动模式选择:FTP主动模式和被动模式的详细介绍可以参考(http://blog.csdn.net/huanggang028/article/details/41248663)。大概意思就是主动模式是客户端向服务端发送PORT命令,然后服务端通过20数据端口连接客户端开启的端口,然后发送数据;被动模式是客户端向服务端发送PASV命令,服务端随机开启一个端口并通知客户端,客户端根据该端口与服务端建立连接,然后发送数据。服务端是两种模式的,使用哪种模式取决于客户端,同时关键点在于网络环境适合用哪种模式,比如客户端在防火墙内,则最好选择被动模式。ftpClient.enterLocalActiveMode()便是配置成主动模式,而ftpClient.enterLocalPassiveMode()则配置成被动模式。
B)文件格式选择:默认是类型是ASCII(普通文本文件),但是为了使得支持任何类型,建议设置成BINARY_FILE_TYPE,并且是在上传和下载操作开始前调用setFileType(int fileType)。
C)上传、下载重载方法的使用选择:比如上传,boolean storeFile(String remote, InputStream local)和OutputStream storeFileStream(String remote),差别是第一个方法如果我们不用关心到底已经从InputStream中传递了多少字节,完全依靠接口内部实现完成输入输出操作,而第二个方法使得我们可以在上传过程中控制传送字节速度等额外操作,比如传送进度的实现便可以依赖此方法。但是,需要注意的是,如果采用了第二个方法来做, 必须靠我们去实现是否上传完毕、下载完毕的事后控制,否则会出现问题。比如我们采用第二个方法,需要手动关闭流,同时,紧接着调用completePendingCommand()方法。如果使用第一个方法不能调用completePendingCommand()方法,因为它一旦被调用, 会一直等待FTP服务器返回226Transfer complete,但是FTP服务器只有在接受流执行close方法时,才会返回。不该调用的时候调用了便会出现僵死现象,同时报错
1 package com.mmall.util; 2 3 import org.apache.commons.net.ftp.FTPClient; 4 import org.slf4j.Logger; 5 import org.slf4j.LoggerFactory; 6 7 import java.io.File; 8 import java.io.FileInputStream; 9 import java.io.IOException; 10 import java.util.List; 11 12 public class FTPUtil { 13 private static final Logger logger = LoggerFactory.getLogger(FTPUtil.class); 14 15 //从配置文件中获得 ip user password 16 private static String ftpIp = PropertiesUtil.getProperty("ftp.server.ip"); 17 private static String ftpUser = PropertiesUtil.getProperty("ftp.user"); 18 private static String ftpPass = PropertiesUtil.getProperty("ftp.pass"); 19 //也可以 new 20 public FTPUtil(String ip,int port,String user,String pwd){ 21 this.ip = ip; 22 this.port = port; 23 this.user = user; 24 this.pwd = pwd; 25 } 26 public static boolean uploadFile(List<File> fileList) throws IOException{ 27 FTPUtil ftpUtil = new FTPUtil(ftpIp,21,ftpUser,ftpPass); 28 logger.info("开始连接 ftp 服务器"); 29 boolean result = ftpUtil.uploadFile("img",fileList); 30 logger.info("开始连接ftp服务器,结束上传,上传结果:{}"); 31 return result; 32 } 33 private boolean uploadFile(String remotePath,List<File> fileList) throws IOException { 34 boolean uploaded = true; 35 FileInputStream fis = null; 36 //连接 ftp 服务器 37 if (connectServer(this.ip,this.port,this.user,this.pwd)){ 38 try { 39 ftpClient.changeWorkingDirectory(remotePath); 40 ftpClient.setBufferSize(1024); 41 ftpClient.setControlEncoding("UTF-8"); 42 ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE); 43 ftpClient.enterLocalPassiveMode(); 44 for(File fileItem : fileList){ 45 fis = new FileInputStream(fileItem); 46 ftpClient.storeFile(fileItem.getName(),fis); 47 } 48 49 } catch (IOException e) { 50 logger.error("上传文件异常",e); 51 uploaded = false; 52 e.printStackTrace(); 53 } finally { 54 if (fis != null){ 55 fis.close(); 56 } 57 ftpClient.disconnect(); 58 } 59 } 60 return uploaded; 61 } 62 63 private boolean connectServer(String ip,int port,String user,String pwd){ 64 65 boolean isSuccess = false; 66 ftpClient = new FTPClient(); 67 try { 68 ftpClient.connect(ip); 69 isSuccess = ftpClient.login(user,pwd); 70 } catch (IOException e) { 71 logger.error("连接FTP服务器异常",e); 72 } 73 return isSuccess; 74 } 75 76 77 private String ip; 78 private int port; 79 private String user; 80 private String pwd; 81 private FTPClient ftpClient; 82 83 public String getIp() { 84 return ip; 85 } 86 87 public void setIp(String ip) { 88 this.ip = ip; 89 } 90 91 public int getPort() { 92 return port; 93 } 94 95 public void setPort(int port) { 96 this.port = port; 97 } 98 99 public String getUser() { 100 return user; 101 } 102 103 public void setUser(String user) { 104 this.user = user; 105 } 106 107 public String getPwd() { 108 return pwd; 109 } 110 111 public void setPwd(String pwd) { 112 this.pwd = pwd; 113 } 114 115 public FTPClient getFtpClient() { 116 return ftpClient; 117 } 118 119 public void setFtpClient(FTPClient ftpClient) { 120 this.ftpClient = ftpClient; 121 } 122 }