packagecom.test.ftp;importjava.io.File;importjava.io.FileOutputStream;importjava.io.IOException;importjava.io.InputStream;importjava.io.OutputStream;importjava.io.PrintWriter;importjava.io.RandomAccessFile;importjava.util.ArrayList;importjava.util.List;importorg.apache.commons.net.PrintCommandListener;importorg.apache.commons.net.ftp.FTP;importorg.apache.commons.net.ftp.FTPClient;importorg.apache.commons.net.ftp.FTPFile;importorg.apache.commons.net.ftp.FTPReply;/*** FTP上传下载文件
* 支持断点续传
*@version: 2009-10-23 下午04:28:48*/publicclassContinueFTP{privateFile file=null;//是否完整保留原文件名privatebooleanisSaveFileName=true;//枚举上传状态publicenumUploadStatus {
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;//删除远程文件失败}//枚举下载状态publicenumDownloadStatus {
Remote_File_Noexist,//远程文件不存在Local_Bigger_Remote,//本地文件大于远程文件Download_From_Break_Success,//断点下载文件成功Download_From_Break_Failed,//断点下载文件失败Download_New_Success,//全新下载文件成功Download_New_Failed;//全新下载文件失败}publicvoidinit(){
}publicFTPClient ftpClient=newFTPClient();publicContinueFTP(){//设置将过程中使用到的命令输出到控制台this.ftpClient.addProtocolCommandListener(newPrintCommandListener(newPrintWriter(System.out)));
}/*** 功能:通过本地文件名指定远程文件名
*@paramlocalFileName
*@return* String
* 范例:*/publicString getRemoteFileName(String localFileName){
String fileName="";//分隔符String sepaRator="\\";if(localFileName.indexOf(sepaRator)<0)
sepaRator="/";//最后分隔符位置intidx=localFileName.lastIndexOf(sepaRator)+1;
fileName=localFileName.substring(idx);returnfileName;
}/*** 功能:检查远程是否存在文件
*@paramremoteFileName 远程文件名
*@return*@throwsIOException
* boolean
* 范例:*/publicbooleanisFileExist(String remoteFileName)throwsIOException{booleanisFileExist=false;//检查远程是否存在文件FTPFile[] files=ftpClient.listFiles(newString(remoteFileName.getBytes("GBK"),"iso-8859-1"));if(files!=null&&files.length>=1){
isFileExist=true;
}returnisFileExist;
}/*** 连接到FTP服务器
*@paramhostname 主机名
*@paramport 端口
*@paramusername 用户名
*@parampassword 密码
*@return是否连接成功
*@throwsIOException*/publicbooleanconnect(String hostname,intport,String username,String password)throwsException{booleanbl=false;try{
ftpClient.connect(hostname, port);
}catch(Exception e){//可具体报错到主机和端口号e.printStackTrace();//throw new BaseException("FTPConnError01",new String[]{"connect",e.getMessage()});}try{//ftpClient.setControlEncoding("GBK");if(FTPReply.isPositiveCompletion(ftpClient.getReplyCode())){if(ftpClient.login(username, password)){
bl=true;
}
}
}catch(Exception e){//可具体报错到用户和密码//throw new BaseException("FTPConnError02",new String[]{"connect",e.getMessage()});e.printStackTrace();
}returnbl;
}/*** 从FTP服务器上下载文件,支持断点续传,上传百分比汇报
*@paramremote 远程文件路径
*@paramlocal 本地文件路径
*@return上传的状态
*@throwsIOException*/publicDownloadStatus download(String remote,String local)throwsException{//设置被动模式ftpClient.enterLocalPassiveMode();//设置以二进制方式传输ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
DownloadStatus result;//检查远程文件是否存在FTPFile[] files=ftpClient.listFiles(newString(remote.getBytes("GBK"),"iso-8859-1"));if(files.length!=1){//throw new BaseException("CellDataInputService",new String[]{"download","远程文件"+remote+"不存在"});System.out.println("远程文件"+remote+"不存在");
}longlRemoteSize=files[0].getSize();
File f=newFile(local);//本地存在文件,进行断点下载if(f.exists()){longlocalSize=f.length();//判断本地文件大小是否大于远程文件大小if(localSize>=lRemoteSize){
System.out.println("本地文件大于远程文件,下载中止");returnDownloadStatus.Local_Bigger_Remote;
}//进行断点续传,并记录状态FileOutputStream out=newFileOutputStream(f,true);
ftpClient.setRestartOffset(localSize);
InputStream in=ftpClient.retrieveFileStream(newString(remote.getBytes("GBK"),"iso-8859-1"));byte[] bytes=newbyte[1024];longstep=lRemoteSize/100;longprocess=localSize/step;intc;while((c=in.read(bytes))!=-1){
out.write(bytes,0,c);
localSize+=c;longnowProcess=localSize/step;if(nowProcess>process){
process=nowProcess;if(process%10==0)
System.out.println("下载进度:"+process);//TODO 更新文件下载进度,值存放在process变量中}
}
in.close();
out.close();booleanisDo=ftpClient.completePendingCommand();if(isDo){
result=DownloadStatus.Download_From_Break_Success;
}else{
result=DownloadStatus.Download_From_Break_Failed;
}
}else{
OutputStream out=newFileOutputStream(f);
InputStream in=ftpClient.retrieveFileStream(newString(remote.getBytes("GBK"),"iso-8859-1"));byte[] bytes=newbyte[1024];longstep=lRemoteSize/100;longprocess=0;longlocalSize=0L;intc;while((c=in.read(bytes))!=-1){
out.write(bytes,0, c);
localSize+=c;longnowProcess=localSize/step;if(nowProcess>process){
process=nowProcess;if(process%10==0)
System.out.println("下载进度:"+process);//TODO 更新文件下载进度,值存放在process变量中}
}
in.close();
out.close();booleanupNewStatus=ftpClient.completePendingCommand();if(upNewStatus){
result=DownloadStatus.Download_New_Success;
}else{
result=DownloadStatus.Download_New_Failed;
}
}returnresult;
}/*** 上传文件到FTP服务器,支持断点续传
*@paramlocal 本地文件名称,绝对路径
*@paramremote 远程文件路径,使用/home/directory1/subdirectory/file.ext 按照Linux上的路径指定方式,支持多级目录嵌套,支持递归创建不存在的目录结构
*@return上传结果
*@throwsIOException*/publicUploadStatus upload(File localFile,String remote)throwsIOException{//设置PassiveMode传输ftpClient.enterLocalPassiveMode();//设置以二进制流的方式传输ftpClient.setFileType(FTP.BINARY_FILE_TYPE);//ftpClient.setControlEncoding("GBK");UploadStatus result;//对远程目录的处理String remoteFileName=remote;if(remote.contains("/")){
remoteFileName=remote.substring(remote.lastIndexOf("/")+1);//创建服务器远程目录结构,创建失败直接返回if(CreateDirecroty(remote, ftpClient)==UploadStatus.Create_Directory_Fail){returnUploadStatus.Create_Directory_Fail;
}
}//检查远程是否存在文件FTPFile[] files=ftpClient.listFiles(newString(remoteFileName.getBytes("GBK"),"iso-8859-1"));if(files!=null&&files.length==1){longremoteSize=files[0].getSize();//File f = new File(local);longlocalSize=localFile.length();if(remoteSize==localSize){returnUploadStatus.File_Exits;
}elseif(remoteSize>localSize){returnUploadStatus.Remote_Bigger_Local;
}//尝试移动文件内读取指针,实现断点续传result=uploadFile(remoteFileName, localFile, ftpClient, remoteSize);//如果断点续传没有成功,则删除服务器上文件,重新上传if(result==UploadStatus.Upload_From_Break_Failed){if(!ftpClient.deleteFile(remoteFileName)){returnUploadStatus.Delete_Remote_Faild;
}
result=uploadFile(remoteFileName, localFile, ftpClient,0);
}
}else{
result=uploadFile(remoteFileName, localFile, ftpClient,0);
}returnresult;
}/*** 断开与远程服务器的连接
*@throwsIOException*/publicvoiddisconnect()throwsIOException{if(this.ftpClient.isConnected()){this.ftpClient.disconnect();
}
}/*** 功能:创建目录
* 若传入路径已经存在,则返回该路径,否则创建
* 目前暂不支持中文列名
*@paramremoteDir
*@return*@throwsIOException
* String
* 范例:*/publicString CreateDirecroty(String remoteDir)throwsIOException{
String fillDir="";
UploadStatus st=CreateDirecroty(remoteDir,this.ftpClient);if(st==UploadStatus.Create_Directory_Success)
fillDir=remoteDir;elsefillDir="";returnfillDir;
}/*** 递归创建远程服务器目录
*@paramremote 远程服务器文件绝对路径
*@paramftpClient FTPClient对象
*@return目录创建是否成功
*@throwsIOException*/publicUploadStatus CreateDirecroty(String remote,FTPClient ftpClient)throwsIOException{
UploadStatus status=UploadStatus.Create_Directory_Success;
String directory=remote.substring(0,remote.lastIndexOf("/")+1);if(!directory.equalsIgnoreCase("/")&&!ftpClient.changeWorkingDirectory(newString(directory.getBytes("GBK"),"iso-8859-1"))){//如果远程目录不存在,则递归创建远程服务器目录intstart=0;intend=0;if(directory.startsWith("/")){
start=1;
}else{
start=0;
}
end=directory.indexOf("/",start);while(true){
String subDirectory=newString(remote.substring(start,end).getBytes("GBK"),"iso-8859-1");if(!ftpClient.changeWorkingDirectory(subDirectory)){if(ftpClient.makeDirectory(subDirectory)){
ftpClient.changeWorkingDirectory(subDirectory);
}else{
System.out.println("创建目录失败");returnUploadStatus.Create_Directory_Fail;
}
}
start=end+1;
end=directory.indexOf("/",start);//检查所有目录是否创建完毕if(end<=start){break;
}
}
}returnstatus;
}/*** 上传文件到服务器,新上传和断点续传
*@paramremoteFile 远程文件名,在上传之前已经将服务器工作目录做了改变
*@paramlocalFile 本地文件File句柄,绝对路径
*@paramprocessStep 需要显示的处理进度步进值
*@paramftpClient FTPClient引用
*@return*@throwsIOException*/publicUploadStatus uploadFile(String remoteFile,File localFile,FTPClient ftpClient,longremoteSize)throwsIOException{
UploadStatus status;//显示进度的上传longstep=localFile.length()/100;longprocess=0;longlocalreadbytes=0L;
RandomAccessFile raf=newRandomAccessFile(localFile,"r");
OutputStream out=ftpClient.appendFileStream(newString(remoteFile.getBytes("GBK"),"iso-8859-1"));//断点续传if(remoteSize>0){
ftpClient.setRestartOffset(remoteSize);
process=remoteSize/step;
raf.seek(remoteSize);
localreadbytes=remoteSize;
}byte[] bytes=newbyte[1024];intc;while((c=raf.read(bytes))!=-1){
out.write(bytes,0,c);
localreadbytes+=c;//TODO 汇报上传状态if(localreadbytes/step!=process){
process=localreadbytes/step;
System.out.println("上传进度:"+process);
}
}
out.flush();
raf.close();
out.close();booleanresult=ftpClient.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;
}returnstatus;
}/*** 功能:获得远程文件列表
*@paramremoteDir 远程路径
*@return* List
* 范例:*/publicListgetRemoteFileList(String remoteDir){
Listlist=newArrayList();
FTPFile[] files;try{
files=ftpClient.listFiles(remoteDir);for(inti=0; i
list.add(files[i].getName());
}
}catch(IOException e) {//TODO Auto-generated catch blocke.printStackTrace();
}returnlist;
}/*** 功能:删除指定远程文件
*@paramfillFileName 包括路径的完整文件名
*@return*@throwsException
* boolean
* 范例:*/publicbooleandeleteFile(String fillFileName)throwsException {booleanbl=false;this.ftpClient.deleteFile(fillFileName);intstatus=this.ftpClient.getReplyCode();if(status==250){
bl=true;
System.out.println("成功删除FTP服务器中文件:"+fillFileName);
}returnbl;
}