開發環境:Jdk 1.8
引入第三方庫:commons-net-2.2.jar(針對第一種方法)
一、基於第三方庫FtpClient的FTP服務器數據傳輸
由於是基於第三方庫,所以這里基本上沒有太多要說明的東西。就是導入第三方庫再調用即可,調用過程從下面的代碼可以參見。為了便於文章的完整性,這也是給出其程序結構圖吧。
圖-1 基於FtpClient的FTP網絡文件傳輸圖
所需要
commons.net-1.4.1.jar
jar包已保存到百度網盤ftptest中。或者http://pan.baidu.com/s/1hq5p7NI
/**
* ftp鏈接常量
*
*/
public class Ftp {
private String ipAddr;//ip地址
private Integer port;//端口號
private String userName;//用戶名
private String pwd;//密碼
private String path;//aaa路徑
public String getIpAddr() {
return ipAddr;
}
public void setIpAddr(String ipAddr) {
this.ipAddr = ipAddr;
}
public Integer getPort() {
return port;
}
public void setPort(Integer port) {
this.port = port;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
}
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPFile; import org.apache.commons.net.ftp.FTPReply; import org.apache.log4j.Logger; public class FtpUtil { private static Logger logger=Logger.getLogger(FtpUtil.class); private static FTPClient ftp; /** * 獲取ftp連接 * @param f * @return * @throws Exception */ public static boolean connectFtp(Ftp f) throws Exception{ ftp=new FTPClient(); boolean flag=false; int reply; if (f.getPort()==null) { ftp.connect(f.getIpAddr(),21); }else{ ftp.connect(f.getIpAddr(),f.getPort()); } ftp.login(f.getUserName(), f.getPwd()); ftp.setFileType(FTPClient.BINARY_FILE_TYPE); reply = ftp.getReplyCode(); if (!FTPReply.isPositiveCompletion(reply)) { ftp.disconnect(); return flag; } ftp.changeWorkingDirectory(f.getPath()); flag = true; return flag; } /** * 關閉ftp連接 */ public static void closeFtp(){ if (ftp!=null && ftp.isConnected()) { try { ftp.logout(); ftp.disconnect(); } catch (IOException e) { e.printStackTrace(); } } } /** * ftp上傳文件 * @param f * @throws Exception */ public static void upload(File f) throws Exception{ if (f.isDirectory()) { ftp.makeDirectory(f.getName()); ftp.changeWorkingDirectory(f.getName()); String[] files=f.list(); for(String fstr : files){ File file1=new File(f.getPath()+"/"+fstr); if (file1.isDirectory()) { upload(file1); ftp.changeToParentDirectory(); }else{ File file2=new File(f.getPath()+"/"+fstr); FileInputStream input=new FileInputStream(file2); ftp.storeFile(file2.getName(),input); input.close(); } } }else{ File file2=new File(f.getPath()); FileInputStream input=new FileInputStream(file2); ftp.storeFile(file2.getName(),input); input.close(); } } /** * 下載鏈接配置 * @param f * @param localBaseDir 本地目錄 * @param remoteBaseDir 遠程目錄 * @throws Exception */ public static void startDown(Ftp f,String localBaseDir,String remoteBaseDir ) throws Exception{ if (FtpUtil.connectFtp(f)) { try { FTPFile[] files = null; boolean changedir = ftp.changeWorkingDirectory(remoteBaseDir); if (changedir) { ftp.setControlEncoding("GBK"); files = ftp.listFiles(); for (int i = 0; i < files.length; i++) { try{ downloadFile(files[i], localBaseDir, remoteBaseDir); }catch(Exception e){ logger.error(e); logger.error("<"+files[i].getName()+">下載失敗"); } } } } catch (Exception e) { logger.error(e); logger.error("下載過程中出現異常"); } }else{ logger.error("鏈接失敗!"); } } /** * * 下載FTP文件 * 當你需要下載FTP文件的時候,調用此方法 * 根據<b>獲取的文件名,本地地址,遠程地址</b>進行下載 * * @param ftpFile * @param relativeLocalPath * @param relativeRemotePath */ private static void downloadFile(FTPFile ftpFile, String relativeLocalPath,String relativeRemotePath) { if (ftpFile.isFile()) { if (ftpFile.getName().indexOf("?") == -1) { OutputStream outputStream = null; try { File locaFile= new File(relativeLocalPath+ ftpFile.getName()); //判斷文件是否存在,存在則返回 if(locaFile.exists()){ return; }else{ outputStream = new FileOutputStream(relativeLocalPath+ ftpFile.getName()); ftp.retrieveFile(ftpFile.getName(), outputStream); outputStream.flush(); outputStream.close(); } } catch (Exception e) { logger.error(e); } finally { try { if (outputStream != null){ outputStream.close(); } } catch (IOException e) { logger.error("輸出文件流異常"); } } } } else { String newlocalRelatePath = relativeLocalPath + ftpFile.getName(); String newRemote = new String(relativeRemotePath+ ftpFile.getName().toString()); File fl = new File(newlocalRelatePath); if (!fl.exists()) { fl.mkdirs(); } try { newlocalRelatePath = newlocalRelatePath + '/'; newRemote = newRemote + "/"; String currentWorkDir = ftpFile.getName().toString(); boolean changedir = ftp.changeWorkingDirectory(currentWorkDir); if (changedir) { FTPFile[] files = null; files = ftp.listFiles(); for (int i = 0; i < files.length; i++) { downloadFile(files[i], newlocalRelatePath, newRemote); } } if (changedir){ ftp.changeToParentDirectory(); } } catch (Exception e) { logger.error(e); } } } public static void main(String[] args) throws Exception{ Ftp f=new Ftp(); f.setIpAddr("1111"); f.setUserName("root"); f.setPwd("111111"); FtpUtil.connectFtp(f); File file = new File("F:/test/com/test/Testng.java"); FtpUtil.upload(file);//把文件上傳在ftp上 FtpUtil.startDown(f, "e:/", "/xxtest");//下載ftp文件測試 System.out.println("ok"); } }
1.FTP的連接及登錄
- public static FtpClient connectFTP(String url, int port, String username, String password) {
- //創建ftp
- FtpClient ftp = null;
- try {
- //創建地址
- SocketAddress addr = new InetSocketAddress(url, port);
- //連接
- ftp = FtpClient.create();
- ftp.connect(addr);
- //登陸
- ftp.login(username, password.toCharArray());
- ftp.setBinaryType();
- } catch (FtpProtocolException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- return ftp;
- }
2.上傳文件到FTP服務器
- public static void upload(String localFile, String ftpFile, FtpClient ftp) {
- OutputStream os = null;
- FileInputStream fis = null;
- try {
- // 將ftp文件加入輸出流中。輸出到ftp上
- os = ftp.putFileStream(ftpFile);
- File file = new File(localFile);
- // 創建一個緩沖區
- fis = new FileInputStream(file);
- byte[] bytes = new byte[1024];
- int c;
- while((c = fis.read(bytes)) != -1){
- os.write(bytes, 0, c);
- }
- System.out.println("upload success!!");
- } catch (FtpProtocolException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- try {
- if(os!=null) {
- os.close();
- }
- if(fis!=null) {
- fis.close();
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
3.從FTP服務器下載文件
- public static void download(String localFile, String ftpFile, FtpClient ftp) {
- InputStream is = null;
- FileOutputStream fos = null;
- try {
- // 獲取ftp上的文件
- is = ftp.getFileStream(ftpFile);
- File file = new File(localFile);
- byte[] bytes = new byte[1024];
- int i;
- fos = new FileOutputStream(file);
- while((i = is.read(bytes)) != -1){
- fos.write(bytes, 0, i);
- }
- System.out.println("download success!!");
- } catch (FtpProtocolException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- try {
- if(fos!=null) {
- fos.close();
- }
- if(is!=null){
- is.close();
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
二、基於Socket的FTP服務器數據傳輸
其實上面的基於第三方包FtpClient的方法中,原理層也是基於Socket來進行通信的。所以,我們當然也可以使用Socket直接來寫這個FtpClient的代碼。下面給出基於Socket通信的結構構架圖。這里有一點需要大家注意一下,我們的FTP協議中有兩個端口(20和21)。通常情況下,我們的21號端口就是平時大家口口相傳的是FTP服務器的端口號,不過其實它只是FTP服務器中的命令端口號。它是負責傳送命令給FTP,一些操作如“登錄”、“改變目錄”、“刪除文件”,依靠這個連接發送命令就可完成。而對於20號端口號(也有可能是其它的一些端口號),對於有數據傳輸的操作,主要是顯示目錄列表,上傳、下載文件,我們需要依靠另一個Socket來完成。
所以在下面的結構圖中,我們可以看到我們有重新獲得端口號的過程,正是這個原因。
圖-2 基於Socket的FTP網絡文件傳輸圖
1.FTP連接
- public void connectFtp() {
- try {
- mFtpClient = new Socket(Config.FTP.HOST_IP, Config.FTP.HOST_PORT);
- mReader = new BufferedReader(new InputStreamReader(mFtpClient.getInputStream()));
- mWriter = new BufferedWriter(new OutputStreamWriter(mFtpClient.getOutputStream()));
- sendCommand("USER " + Config.FTP.FTP_USERNAME);
- sendCommand("PASS " + Config.FTP.FTP_PASSWD);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
2.向FTP服務器發送命令
- private void sendCommand(String command) throws IOException {
- if (Tools.StringTools.isEmpty(command)) {
- return;
- }
- if (mFtpClient == null) {
- return;
- }
- mWriter.write(command + "\r\n");
- mWriter.flush();
- }
3.向FTP服務器上傳文件
- public void uploadFile(String localPath, String ftpPath) throws IOException {
- // 進入被動模式
- sendCommand("PASV");
- // 獲得ip和端口
- String response = readNewMessage();
- String[] ipPort = getIPPort(response);
- String ip = ipPort[0];
- int port = Integer.parseInt(ipPort[1]);
- // 建立數據端口的連接
- Socket dataSocket = new Socket(ip, port);
- sendCommand("STOR " + ftpPath);
- // 上傳文件前的准備
- File localFile = new File(localPath);
- OutputStream outputStream = dataSocket.getOutputStream();
- FileInputStream fileInputStream = new FileInputStream(localFile);
- // 上傳文件
- int offset;
- byte[] bytes = new byte[1024];
- while ((offset = fileInputStream.read(bytes)) != -1) {
- outputStream.write(bytes, 0, offset);
- }
- System.out.println("upload success!!");
- // 上傳文件后的善后工作
- outputStream.close();
- fileInputStream.close();
- dataSocket.close();
- }
4.從FTP服務器下載文件
- public void downloadFile(String localPath, String ftpPath) throws IOException {
- // 進入被動模式
- sendCommand("PASV");
- // 獲得ip和端口
- String response = readNewMessage();
- String[] ipPort = getIPPort(response);
- String ip = ipPort[0];
- int port = Integer.parseInt(ipPort[1]);
- // 建立數據端口的連接
- Socket dataSocket = new Socket(ip, port);
- sendCommand("RETR " + ftpPath);
- // 下載文件前的准備
- File localFile = new File(localPath);
- InputStream inputStream = dataSocket.getInputStream();
- FileOutputStream fileOutputStream = new FileOutputStream(localFile);
- // 下載文件
- int offset;
- byte[] bytes = new byte[1024];
- while ((offset = inputStream.read(bytes)) != -1) {
- fileOutputStream.write(bytes, 0, offset);
- }
- System.out.println("download success!!");
- // 下載文件后的善后工作
- inputStream.close();
- fileOutputStream.close();
- dataSocket.close();
- }
5.斷開FTP服務器連接
- public void disconnectFtp() {
- if (mFtpClient == null) {
- return;
- }
- if (!mFtpClient.isConnected()) {
- return;
- }
- try {
- mFtpClient.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }