您的位置:首页 > 编程语言 > PHP开发

【FTP】FTP文件上传下载-支持断点续传

2017-01-05 17:11 519 查看
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();

}

}

[/code]

参考链接

官方Demo: http://commons.apache.org/proper/commons-net/examples/ftp/FTPClientExample.java https://my.oschina.net/csmw00/blog/676049 (可参考如何实现进度监控)http://yujie020.blog.51cto.com/2827685/655338

来自为知笔记(Wiz)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: