【FTP】FTP文件上傳下載-支持斷點續傳

  • Jar包:apache的commons-net包;
  • 支持斷點續傳
  • 支持進度監控(有時出不來,搞不清緣由)

相關知識點

  • 編碼格式: UTF-8等;
  • 文件類型: 包括[BINARY_FILE_TYPE(經常使用)]和[ASCII_FILE_TYPE]兩種;
  • 數據鏈接模式:通常使用LocalPassiveMode模式,由於大部分客戶端都在防火牆後面;
              1. LocalPassiveMode:服務器端打開數據端口,進行數據傳輸;
              2. LocalActiveMode:客戶端打開數據端口,進行數據傳輸;
  • 系統類型:UNIX/WINDOWS等,默認爲Unix

流程

  • 步驟1: 建立FTPClient對象,設置ftpClient屬性:如編碼格式、鏈接超時、文件上傳下載進度監聽器等;
  • 步驟2: 使用ftpClient鏈接遠程server:connect();
  • 步驟3: 獲取connect()的返回碼getReplyCode(),判斷是否鏈接成功:isPositiveCompletion();
  • 步驟4: 登陸遠程server:login(),並轉到相應目錄,必要時要遞歸建立目錄;
  • 步驟5: 設置ftpClient屬性:如緩存大小、文件類型、超時時間、數據鏈接模式等;
  • 步驟6: ftp相關操做:如文件上傳、下載等;
  • 步驟7: 斷開鏈接,釋放資源:logout()/disconnect();

程序

FTP鏈接和登陸



文件上傳



文件下載


測試程序


完整程序

   
   
   
   
package com.sssppp.Communication;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.io.PrintWriter;import java.io.RandomAccessFile;import org.apache.commons.net.PrintCommandListener;import org.apache.commons.net.ftp.FTP;import org.apache.commons.net.ftp.FTPClient;import org.apache.commons.net.ftp.FTPClientConfig;import org.apache.commons.net.ftp.FTPFile;import org.apache.commons.net.ftp.FTPReply;import org.apache.commons.net.io.CopyStreamEvent;import org.apache.commons.net.io.CopyStreamListener;/** * FTP進行文件上傳和下載; * 支持斷點續傳; */public final class FTPUtil { private final FTPClient ftp = new FTPClient(); /** * * @param hostname * 如:IP * @param port * @param username * @param password * @return * @throws IOException */ public boolean connect(String hostname, int port, String username, String password) throws IOException { boolean debug = false; if (debug) { // 設置將過程當中使用到的命令輸出到控制檯 this.ftp.addProtocolCommandListener(new PrintCommandListener( new PrintWriter(System.out), true)); } //設置系統類型 final FTPClientConfig config = new FTPClientConfig( FTPClientConfig.SYST_UNIX); this.ftp.configure(config); try { this.ftp.connect(hostname, port); if (!FTPReply.isPositiveCompletion(this.ftp.getReplyCode())) { this.ftp.disconnect(); System.err.println("FTP server refused connection."); return false; } } catch (IOException e) { if (this.ftp.isConnected()) { try { this.ftp.disconnect(); } catch (IOException f) { } } System.err.println("Could not connect to server."); e.printStackTrace(); return false; } if (!this.ftp.login(username, password)) { this.ftp.logout(); System.err.println("Could not login to server."); return false; } return true; } public void disconnect() throws IOException { if (this.ftp.isConnected()) { try { this.ftp.logout(); this.ftp.disconnect(); } catch (IOException f) { } } } /** * * @param absSrcFileName * @param destDir * @param destFileName * @throws IOException */ public void upLoadByFtp(String absSrcFileName, String destDir, String destFileName) throws IOException { // 建立並轉到工做目錄 String absDstDir = this.ftp.printWorkingDirectory() + "/" + destDir; absDstDir = absDstDir.replaceAll("//", "/"); createDirectory(absDstDir, this.ftp); // 設置各類屬性 this.ftp.setFileType(FTP.BINARY_FILE_TYPE); // Use passive mode as default because most of us are behind firewalls these days. this.ftp.enterLocalPassiveMode(); this.ftp.setControlEncoding("utf-8"); this.ftp.setBufferSize(1024); // 進度監聽 File srcFile = new File(absSrcFileName); this.ftp.setCopyStreamListener(new MyCopyStreamListener(srcFile.length())); FTPFile[] files = this.ftp.listFiles(destFileName); if (files.length == 1) {// 斷點續傳 long dstFileSize = files[0].getSize(); if (srcFile.length() <= dstFileSize) {// 文件已存在 return; } boolean b = uploadFile(destFileName, srcFile, this.ftp, dstFileSize); if (!b) {// 若是斷點續傳沒有成功,則刪除服務器上文件,從新上傳 if (this.ftp.deleteFile(destFileName)) { uploadFile(destFileName, srcFile, this.ftp, 0); }else { System.err.println("Delete file fail."); } } } else { uploadFile(destFileName, srcFile, this.ftp, 0); } } /** * * @param remoteFileName * @param localFileName * @throws IOException */ public void downLoadByFtp(String remoteFileName, String localFileName) throws IOException { InputStream input = null; FileOutputStream fos = null; // 設置各類屬性 this.ftp.setBufferSize(1024); this.ftp.setDataTimeout(1000 * 10); this.ftp.setFileType(FTPClient.BINARY_FILE_TYPE); this.ftp.enterLocalPassiveMode(); // 判斷遠程文件是否存在 FTPFile[] files = this.ftp.listFiles(remoteFileName); if (files.length != 1) { System.err.println("Remote file not exist."); return; } //進度監聽 long remoteSize = files[0].getSize(); this.ftp.setCopyStreamListener(new MyCopyStreamListener(remoteSize)); File file = new File(localFileName); if (file.exists()) { long localSize = file.length(); if (localSize >= remoteSize) { return; } System.out.println("@@@Break point download.@@@"); fos = new FileOutputStream(file, true);// append模式 this.ftp.setRestartOffset(localSize); } else { fos = new FileOutputStream(file); // override模式 } input = this.ftp.retrieveFileStream(remoteFileName); byte[] b = new byte[8192]; int n = 0; while (-1 != (n = input.read(b))) { if (Thread.currentThread().isInterrupted()) { break; } fos.write(b, 0, n); } if (input != null) { input.close(); } if (fos != null) { fos.flush(); fos.close(); } if (!this.ftp.completePendingCommand()) { System.err.println("Download file fail."); this.ftp.logout(); this.ftp.disconnect(); } } /** * * @param destFileName * @param srcFile * @param ftpClient * @param dstFileSize 文件寫入的起始位置; >0:表示斷點續傳,<=0:表示上傳新文件 * @return * @throws IOException */ private boolean uploadFile(String destFileName, File srcFile, FTPClient ftpClient, long dstFileSize) throws IOException { RandomAccessFile input = null; OutputStream fout = null; input = new RandomAccessFile(srcFile, "r"); // 只讀模式 if (dstFileSize > 0) {// 斷點續傳 fout = ftpClient.appendFileStream(destFileName); input.seek(dstFileSize); ftpClient.setRestartOffset(dstFileSize); } else { fout = ftpClient.storeFileStream(destFileName); } byte[] b = new byte[8192]; // 緩存大小 int n = 0; while (-1 != (n = input.read(b))) { if (Thread.currentThread().isInterrupted()) { break; } fout.write(b, 0, n); } if (input != null) { input.close(); } if (fout != null) { fout.flush(); fout.close(); } if (!ftpClient.completePendingCommand()) { System.err.println("Upload file fail."); ftpClient.logout(); ftpClient.disconnect(); return false; } return true; } /** * FTP服務器上建立並轉到工做目錄 * * @param relativePath * 相對工做路徑,不包含文件名:如 dd/11/22/33 * @param ftpClient * 錄建立是否成功 * @return * @throws IOException */ private boolean createDirectory(String relativePath, FTPClient ftpClient) throws IOException { if (!relativePath.startsWith("/")) { relativePath = "/" + relativePath; } String dir = (ftpClient.printWorkingDirectory().equals("/") ? "" : ftpClient.printWorkingDirectory()) + relativePath; if (!ftpClient.changeWorkingDirectory(dir)) { //目錄不存在,則建立各級目錄 for (String subDir : relativePath.split("/")) { if (!subDir.equals("")) { String newDir = ftpClient.printWorkingDirectory() + "/" + subDir; ftpClient.mkd(newDir); if (!ftpClient.changeWorkingDirectory(newDir)) { return false; } } } } return true; } /** * 進度監聽器 */ private class MyCopyStreamListener implements CopyStreamListener { private long totalSize = 0; private long percent = -1; // 進度 /** * 文件的總大小 * @param totalSize */ public MyCopyStreamListener(long totalSize) { super(); this.totalSize = totalSize; } @Override public void bytesTransferred(CopyStreamEvent event) { bytesTransferred(event.getTotalBytesTransferred(), event.getBytesTransferred(), event.getStreamSize()); } //totalBytesTransferred:當前總共已傳輸字節數; //bytesTransferred:最近一次傳輸字節數 @Override public void bytesTransferred(long totalBytesTransferred, int bytesTransferred, long streamSize) { if (percent >= totalBytesTransferred * 100 / totalSize) { return; } percent = totalBytesTransferred * 100 / totalSize; System.out.println("Completed " + totalBytesTransferred + "(" + percent + "%) out of " + totalSize + "."); } } public static void main(String[] args) throws IOException { String hostname = "10.180.137.241"; String username = "xxx"; String password = "xxx"; int port = 21; FTPUtil ftp = new FTPUtil(); //上傳文件 String absSrcFileName = "C:\\tmp\\m2eclipse1.zip"; String destDir = "ww/11/22/33"; String destFileName = "m2eclipse1.zip"; ftp.connect(hostname, port, username, password); ftp.upLoadByFtp(absSrcFileName, destDir, destFileName); ftp.disconnect(); // 下載文件 String localFileName = "C:\\tmp\\m2eclipse-download3333.zip"; String remoteFileName = "/ww/11/22/33/m2eclipse.zip"; ftp.connect(hostname, port, username, password); ftp.downLoadByFtp(remoteFileName, localFileName); ftp.disconnect(); }}

參考連接





相關文章
相關標籤/搜索