设为首页 收藏本站
查看: 1690|回复: 0

[经验分享] 使用commons-net包写的一个FTP上传下载类,支持断点续传,可上传整个目录

[复制链接]

尚未签到

发表于 2016-6-11 01:27:46 | 显示全部楼层 |阅读模式
  在http://zhouzaibao.iyunv.com/blog/346000基础上进行了修改
  
  利用org.apache.commons.net.ftp包实现一个简单的ftp客户端实用类。主要实现一下功能
  1.支持上传下载。支持断点续传
  2.支持对于中文目录及中文文件创建的支持。
  具体请看代码,上面有详细的注释。简化版本请参见http://zhouzaibao.iyunv.com/blog/342766
  
  枚举类UploadStatus代码:
  

public enum DownloadStatus {
REMOTE_FILE_NOEXIST, // 远程文件不存在
LOCAL_BIGGER_REMOTE, // 本地文件大于远程文件
DOWNLOAD_FROM_BREAK_SUCCESS, // 断点下载文件成功
DOWNLOAD_FROM_BREAK_FAILED, // 断点下载文件失败
DOWNLOAD_NEW_SUCCESS, // 全新下载文件成功
DOWNLOAD_NEW_FAILED; // 全新下载文件失败
}
  
  枚举类DownloadStatus代码:
  

public enum UploadStatus {
CREATE_DIRECTORY_FAIL, // 远程服务器相应目录创建失败
CREATE_DIRECTORY_SUCCESS, // 远程服务器闯将目录成功
UPLOAD_NEW_FILE_SUCCESS, // 上传新文件成功
UPLOAD_NEW_FILE_FAILED, // 上传新文件失败
FILE_EXITS, // 文件已经存在
REMOTE_BIGGER_LOCAL, // 远程文件大于本地文件
UPLOAD_FROM_BREAK_SUCCESS, // 断点续传成功
UPLOAD_FROM_BREAK_FAILED, // 断点续传失败
DELETE_REMOTE_FAILD; // 删除远程文件失败
}
  
  流及文件操作工具类的代码:
  


public class FileUtil {
/**
* 文件拷贝
*
* @param insm
* @param outsm
* @throws IOException
*/
public static void copyFile(File srcFile, File destFile) throws IOException {
if (!srcFile.exists()) {
throw new FileNotFoundException(srcFile.getName() + "不存在!");
}
if (!destFile.exists()) {
destFile.createNewFile();
}
InputStream in = new FileInputStream(srcFile);
OutputStream out = new FileOutputStream(destFile);
copyStream(in, out);
}
/**
* 流拷贝,通过对流的操作完成
*
* @param insm
* @param outsm
* @throws IOException
*/
public static void copyStream(InputStream insm, OutputStream outsm)
throws IOException {
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
bis = new BufferedInputStream(insm);
bos = new BufferedOutputStream(outsm);
byte[] b = new byte[8192];
int readBytes = -1;
while ((readBytes = bis.read(b)) != -1) {
bos.write(b, 0, readBytes);
}
} catch (IOException e) {
e.printStackTrace();
throw e;
} finally {
if (bis != null)
bis.close();
if (bos != null)
bos.close();
}
}
}

  
  核心类FTPOperationProccessor代码:
  

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import cn.com.servyou.ftpuploadtool.status.DownloadStatus;
import cn.com.servyou.ftpuploadtool.status.UploadStatus;
import cn.com.servyou.ftpuploadtool.util.FileUtil;
/**
* <p>
* Title: FTPOperationProcessor
* </p>
*
* <p>
* Description: FTP操作处理类
* </p>
*
* <p>
* Copyright: Copyright (c) 2010
* </p>
*
* @author servyou
*
* @version 1.0
*/
public class FTPOperationProcessor {
private FTPClient client = new FTPClient();
/** 默认编码 */
public final static String ENCODING = "GBK";
/** FTP传输用的编码 */
public final static String FTP_ENCODING = "ISO-8859-1";
/** 目录前缀 */
public final static String PREFIX = "/";
public FTPOperationProcessor() {
super();
}
/**
* 连接FTP服务器
*
* @param hostname
*            服务器IP,或主机名
* @param port
*            端口号
* @param username
*            用户名
* @param password
*            密码
* @return 连接成功返回true,失败返回false
* @throws IOException
*/
public boolean connect(String hostname, int port, String username,
String password) throws IOException {
int reply;
client.connect(hostname);
System.out.println("Connected to " + hostname + ".");
System.out.println(client.getReplyString());
reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
client.disconnect();
System.out.println("FTP服务器拒绝连接!");
throw new IOException("FTP服务器拒绝连接!");
} else {
if (client.login(username, password)) {
client.setListHiddenFiles(true);
return true;
}
}
return false;
}
/**
* 用户登出,并关闭连接
*
* @throws IOException
*/
public void disConnect() throws IOException {
if (client.isConnected()) {
client.logout();
client.disconnect();
}
}
/**
* 遍历服务器的某一目录
*
* @param pathname
*            FTP服务器的路径,如/dir1/dir2/
* @throws IOException
*/
public void traverseDirectory(String pathname) throws IOException {
client.changeWorkingDirectory(pathname);
FTPFile[] fileList = client.listFiles(pathname);
traverse(fileList);
}
/**
* 遍历FTP服务器的目录
*
* @param ftpClient
*            FTPClient
* @param fileList
*            文件列表
* @throws IOException
*/
private void traverse(FTPFile[] fileList) throws IOException {
String tempDir = null;
for (FTPFile file : fileList) {
if (file.getName().equals(".") || file.getName().equals("..")) {
continue;
}
if (file.isDirectory()) {
System.out.println("***************** Directory: " + file.getName()
+ "  Start **************");
tempDir = client.printWorkingDirectory();
if (tempDir.matches("^((/\\w+))+$"))
tempDir += "/" + file.getName();
else
tempDir += file.getName();
client.changeWorkingDirectory(new String(tempDir.getBytes(ENCODING),
FTP_ENCODING));
traverse(client.listFiles(tempDir));
// 不是目录,是文件的情况
System.out.println("***************** Directory:" + file.getName()
+ "   End **************\n");
} else {
System.out.println("FileName:" + file.getName() + " FileSize:"
+ file.getSize() / (1024) + "KB" + " CreateTime:"
+ file.getTimestamp().getTime());
}
}
// 遍历完当前目录,就要将工作目录改为当前目录的父目录
client.changeToParentDirectory();
}
/**
* 下载单个文件
*
* @param remote
*            远端文件
* @param local
*            本地文件
* @throws IOException
*/
public DownloadStatus download(String remote, File localFile)
throws IOException {
client.enterLocalPassiveMode();
client.setFileType(FTPClient.BINARY_FILE_TYPE);
DownloadStatus result = null;
// 检查远程文件是否存在
FTPFile[] files = client.listFiles(new String(remote.getBytes(ENCODING),
FTP_ENCODING));
if (files.length != 1) {
System.out.println("远程文件不存在");
return DownloadStatus.REMOTE_FILE_NOEXIST;
}
long lRemoteSize = files[0].getSize();
// 本地存在文件,进行断点下载
if (localFile.exists()) {
long localSize = localFile.length();
// 判断本地文件大小是否大于远程文件大小
if (localSize >= lRemoteSize) {
System.out.println("本地文件大于远程文件,下载中止");
return DownloadStatus.LOCAL_BIGGER_REMOTE;
}
// 进行断点续传,并记录状态
FileOutputStream out = new FileOutputStream(localFile, true);
client.setRestartOffset(localSize);
InputStream in = client.retrieveFileStream(new String(remote
.getBytes(ENCODING), FTP_ENCODING));
FileUtil.copyStream(in, out);
boolean isDo = client.completePendingCommand();
if (isDo) {
result = DownloadStatus.DOWNLOAD_FROM_BREAK_SUCCESS;
} else {
result = DownloadStatus.DOWNLOAD_FROM_BREAK_FAILED;
}
} else {
localFile.createNewFile();
FileOutputStream out = new FileOutputStream(localFile);
InputStream in = client.retrieveFileStream(new String(remote
.getBytes(ENCODING), FTP_ENCODING));
FileUtil.copyStream(in, out);
}
return result;
}
/**
* 上传文件到FTP服务器,支持断点续传
*
* @param local
*            本地文件名称,绝对路径
* @param remote
*            远程文件路径,使用/home/directory1/subdirectory/file.ext
*            按照Linux上的路径指定方式,支持多级目录嵌套,支持递归创建不存在的目录结构
* @return 上传结果
* @throws IOException
*/
public UploadStatus upload(String local, String remote) throws IOException {
// 设置PassiveMode传输
client.enterLocalPassiveMode();
// 设置以二进制流的方式传输
client.setFileType(FTPClient.BINARY_FILE_TYPE);
client.setControlEncoding(ENCODING);
UploadStatus result;
// 对远程目录的处理
String remoteFileName = remote;
if (remote.contains("/")) {
remoteFileName = remote.substring(remote.lastIndexOf("/") + 1);
// 创建服务器远程目录结构,创建失败直接返回
// 以下两句存在问题??
// if (createDirectory(remote) == UploadStatus.CREATE_DIRECTORY_FAIL) {
// return UploadStatus.CREATE_DIRECTORY_FAIL;
// }
}
// 检查远程是否存在文件
FTPFile[] files = client.listFiles(new String(remoteFileName
.getBytes(ENCODING), FTP_ENCODING));
if (files != null && files.length == 1) {
long remoteSize = files[0].getSize();
File f = new File(local);
long localSize = f.length();
if (remoteSize == localSize) {
return UploadStatus.FILE_EXITS;
} else if (remoteSize > localSize) {
return UploadStatus.REMOTE_BIGGER_LOCAL;
}
// 尝试移动文件内读取指针,实现断点续传
result = uploadFile(remoteFileName, f, remoteSize);
// 如果断点续传没有成功,则删除服务器上文件,重新上传
if (result == UploadStatus.UPLOAD_FROM_BREAK_FAILED) {
if (!client.deleteFile(remoteFileName)) {
return UploadStatus.DELETE_REMOTE_FAILD;
}
result = uploadFile(remoteFileName, f, 0);
}
} else {
result = uploadFile(remoteFileName, new File(local), 0);
}
return result;
}
/**
* 上传单个文件,断点续传功能
*
* @param remote
*            远程文件
* @param localFile
*            本地文件
* @throws IOException
*/
public UploadStatus uploadFile(String remote, File localFile, long remoteSize)
throws IOException {
UploadStatus status = null;
long localreadbytes = 0l;
RandomAccessFile raf = new RandomAccessFile(localFile, "r");
OutputStream out = client.appendFileStream(new String(remote
.getBytes(ENCODING), FTP_ENCODING));
// 断点续传,根据FTP服务器上文件与本地机器上文件的大小比较来判断
if (remoteSize > 0) {
client.setRestartOffset(remoteSize);
raf.seek(remoteSize);
localreadbytes = remoteSize;
}
byte[] bytes = new byte[8096];
int c;
while ((c = raf.read(bytes)) != -1) {
out.write(bytes, 0, c);
localreadbytes += c;
}
if (out != null)
out.flush();
if (raf != null)
raf.close();
if (out != null)
out.close();
boolean result = client.completePendingCommand();
if (remoteSize > 0) {
status = result ? UploadStatus.UPLOAD_FROM_BREAK_SUCCESS
: UploadStatus.UPLOAD_FROM_BREAK_FAILED;
} else {
status = result ? UploadStatus.UPLOAD_NEW_FILE_SUCCESS
: UploadStatus.UPLOAD_NEW_FILE_FAILED;
}
return status;
}
/**
* 创建目录,(远程目录格式必须是/aaa/bbb/ccc/ddd/的形式)
*
* @param remote
*            远程目录路径
* @throws IOException
*/
public UploadStatus createDirectory(String remote) throws IOException {
int start = 0, end = 0;
start = remote.startsWith("/") ? 1 : 0;
end = remote.indexOf("/", start);
for (; start < end;) {
String subDirectory = remote.substring(start, end);
if (!client.changeWorkingDirectory(new String(subDirectory
.getBytes(ENCODING), FTP_ENCODING))) {
// 目录不存在则在服务器端创建目录
if (!client.makeDirectory(new String(subDirectory.getBytes(ENCODING),
FTP_ENCODING))) {
return UploadStatus.CREATE_DIRECTORY_FAIL;
} else {
client.changeWorkingDirectory(new String(subDirectory
.getBytes(ENCODING), FTP_ENCODING));
}
}
start = end + 1;
end = remote.indexOf("/", start);
}
return UploadStatus.CREATE_DIRECTORY_SUCCESS;
}
/**
* 递归遍历本地机器的要上传的目录,遍历的同时,在FTP服务器上创建目录
* (如果在FTP服务器上目录不存在的话),上传文件
*
* @param directory
*            本地目录
* @throws IOException
*/
private void traverseLocalDirectory(File directory) throws IOException {
File[] files = directory.listFiles();
if (files == null || files.length == 0) {
client.changeToParentDirectory();
return;
}
for (File file : files) {
if (file.isDirectory()) {
String directoryName = file.getName();
client.makeDirectory(new String(directoryName.getBytes(ENCODING),
FTP_ENCODING));
client.changeWorkingDirectory(new String(directoryName
.getBytes(ENCODING), FTP_ENCODING));
traverseLocalDirectory(file);
} else {
System.out.println("FileName : " + file.getName());
upload(file.getAbsolutePath(), client.printWorkingDirectory() + "/"
+ file.getName());
}
}
client.changeToParentDirectory();
}
/**
* 上传本地机器的某一目录到FTP服务器的某一路径
*
* @param remoteBasePath
*            FTP服务器的一个路径
* @param localRootDirectoryPath
*            本地机器需要上传的目录路径
* @throws IOException
*/
public UploadStatus uploadDirectory(String remoteBasePath,
String localDirectoryPath) throws IOException {
if (createDirectory(remoteBasePath) == UploadStatus.CREATE_DIRECTORY_FAIL) {
return UploadStatus.CREATE_DIRECTORY_FAIL;
// remoteBasePath FTP服务器上基目录,创建成功的话
} else {
if (client.changeWorkingDirectory(new String(remoteBasePath
.getBytes(ENCODING), FTP_ENCODING))) {
File localDirectory = new File(localDirectoryPath);
traverseLocalDirectory(localDirectory);
return UploadStatus.CREATE_DIRECTORY_SUCCESS;
} else {
return UploadStatus.CREATE_DIRECTORY_FAIL;
}
}
}
}
  
  
  使用方法简介:
  
  1.需要创建目录:
  

FTPOperationProcessor processor = new FTPOperationProcessor();
try {
boolean flag = processor.connect("192.168.30.190", 21, "anonymous", "");
if (flag == false) {
System.out.println("连接服务器失败");
processor.disConnect();
} else {
processor.createDirectory("/中1/中文的/信息/还是中文的/目录是中文的/xx林寺xxa11/");
}
} catch (IOException e) {
e.printStackTrace();
}
  
  则可在FTP服务器的根目录生成目录

/中1/中文的/信息/还是中文的/目录是中文的/xx林寺xxa11
  
  2.上传整个目录到FTP服务器的某一目录:
  

processor.uploadDirectory("/Jay Chang/Study/Example/", "D:\\My Documents\\Study\\Example\\");
  
  3.下载某一文件到本地:
  
  

processor.download("/backup/sys.gho", "f:\\sys.gho");
  
  
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-228744-1-1.html 上篇帖子: .Net框架集WebClient类向WinCE平台上传文件(FTP方式)延迟15秒释疑 下篇帖子: 用Java来实现FTP服务器应用的详细讲解
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表