`
lp895876294
  • 浏览: 284743 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

基于Ftp/Sftp协议的文件服务器数据传输

    博客分类:
  • JAVA
 
阅读更多

在项目中将应用服务器和文件服务器分开,能够增加项目的可维护性。本例分别使用FTP协议和SFTP协议在Windows Server 2008和Linux系统实现对文件的上传、下载和删除操作。

服务接口如下:

public interface FileManageDao {
	/**
	 * 上传文件
	 * @param inputStream:文件输入流
	 * @param fileName:上传文件名称
	 */
	public void upload(InputStream inputStream,String directory,String fileName) ;
	/**
	 * 下载文件
	 * @param outputStream:文件输出流
	 * @param fileName:下载文件名称
	 */
	public void download(OutputStream outputStream,String directory,String fileName) ;
	/**
	 * 获取文件的输入流
	 * @param directory
	 * @param fileName
	 * @return
	 */
	public InputStream getAttachmentFile(String directory,String fileName);
	/**
	 * 根据文档全名删除文件
	 * @param fileName
	 */
	public void delete(String directory,String fileName) ;
        /**
	 * 判断文件是否存在
	 * @param directory
	 * @param fileName
	 * @return
	 */
	public boolean isExist(String directory,String fileName) ;
}

服务接口模板类:

public abstract class FileManageDaoTemplate implements FileManageDao {
	//主机ip
    public String host="" ;
    //端口号,默认为22
    public int port = 22 ;
    //服务器用户名,默认为root
    public String userName="root" ;
    //服务器密码
    public String password ;
    //服务器上传地址
    public String targetBaseLocation = "chrhc" ;
    //服务器连接超时时间(ms),默认60000
    public int timeout = 60000;
	
	public void setTargetBaseLocation(String targetBaseLocation) {
		if(!StringUtils.hasLength(targetBaseLocation)){
			return ;
		}
		targetBaseLocation = StringUtils.trimLeadingCharacter(targetBaseLocation, '/') ;
		targetBaseLocation = StringUtils.trimTrailingCharacter(targetBaseLocation, '/') ;
		
		this.targetBaseLocation = targetBaseLocation ;
	}
      ....set and get method.....
}

 下面在不同的系统分别采用不同的方式实现:

1.Windows 2008 Server下FTP协议

在Windows下选择使用FTP协议的原因是FTP是Windows自带的服务,只需要通过配置开启FTP服务即可,不需要第三方的安装包。Windows 2008下FTP配置见附件。

使用第三方免费安装包freeftpd也可以实现Windows系统下的FTP、SSH和SFTP服务,但是需要在软件界面中做相应的配置。

JAR包:使用Apache的FTP开源组件commons-net,添加如下Maven依赖:

  <dependency>
      <groupId>commons-net</groupId>
      <artifactId>commons-net</artifactId>
      <version>3.3</version>
  </dependency>

 文件上传模板类实现:

public class FileManageDaoImplByFTP extends FileManageDaoTemplate {
	/**
	 * 获取ftp客户端连接
	 * @return
	 * @throws SocketException
	 * @throws IOException
	 */
	public FTPClient getFtpClient(String directory) throws SocketException, IOException{
		FTPClient ftpClient = new FTPClient();
		ftpClient.connect(host, port);
		ftpClient.setConnectTimeout(timeout);
		boolean loginFlag = ftpClient.login(userName, password) ;
		if(!loginFlag){
			throw new SocketException("ftp login error ,please check setting .") ;
		}
		//设置文件上传目录
		if(StringUtils.hasLength(directory.trim())){
			directory = targetBaseLocation+"/"+StringUtils.trimLeadingCharacter(directory, '/');
		}else{
			directory = targetBaseLocation ;
		}
		//设置上传目录
		boolean flag = ftpClient.changeWorkingDirectory(directory) ;
		//如果目录不存在,则创建目录
		if(!flag){
			String path = null ;
			for (String folderName : directory.split("/")) {
				if(path==null){
					path = folderName ;
				}else{
					path += "/"+folderName ;
				}
				ftpClient.makeDirectory(path);
			}
			flag = ftpClient.changeWorkingDirectory(path) ;
		}
		
		ftpClient.setBufferSize(1024); 
		ftpClient.setControlEncoding("utf-8");
		//设置文件类型(二进制)       
		ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE); 
//设置ftp上传模式为client向server传
		ftpClient.enterLocalPassiveMode(); 
		return ftpClient ;
	}

	@Override
	public void upload(InputStream inputStream,String directory, String fileName) {
		FTPClient ftpClient = null ;
		try {
			ftpClient = getFtpClient(directory);
			//文件名称使用数字+英文,使用汉字会有乱码
			boolean flag = ftpClient.storeFile(new String(fileName.getBytes("utf-8"),"iso-8859-1"), inputStream); 
if(!flag){
				throw new Exception("上传文件 "+fileName+" 失败。") ;
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			//关闭连接
	        IOUtils.closeQuietly(inputStream);       
	        close(ftpClient); 
		}
	}

	@Override
	public void download(OutputStream outputStream,String directory, String fileName){
		FTPClient ftpClient = null ;
		try {
			ftpClient = getFtpClient(directory);
			boolean fileIsExist = isExist(ftpClient, fileName) ;
			if(fileIsExist){
				boolean flag = ftpClient.retrieveFile(fileName, outputStream) ;
				if(!flag){
					throw new Exception("下载文件 "+fileName+" 失败。") ;
				}
			}else{
				throw new Exception("FTP服务器文件 "+fileName+" 不存在.......") ;
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			System.out.println(e.getMessage());
		}finally{
			close(ftpClient);    
		}
	}

	@Override
	public void delete(String directory, String fileName) {
		FTPClient ftpClient = null ;
		try {
			ftpClient = getFtpClient(directory);
			boolean flag = ftpClient.deleteFile(new String(fileName.getBytes("utf-8"),"iso-8859-1"));
if(!flag){
				throw new Exception("删除文件 "+fileName+" 失败。") ;
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			//关闭连接
			close(ftpClient);  
		}
	}
	
	public InputStream getAttachmentFile(String directory,String fileName){
		FTPClient ftpClient = null ;
		InputStream inputStream = null; 
		try {
			ftpClient = getFtpClient(directory);
			boolean fileIsExist = isExist(ftpClient, fileName) ;
			if(fileIsExist){
				inputStream = ftpClient.retrieveFileStream(fileName);
			}else{
				throw new Exception("FTP服务器文件 "+fileName+" 不存在.......") ;
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			System.out.println(e.getMessage());
		}finally{
			//关闭连接
			close(ftpClient);  
		}
		return inputStream ;
	}
	
	public void close(FTPClient ftpClient){
		if(ftpClient!=null){
			try {
				ftpClient.disconnect();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
/**
	 * 判断ftpClient当前所在目录下,名称为fileName的文件是否存在
	 * @param ftpClient
	 * @param fileName
	 * @return
	 */
	public boolean isExist(FTPClient ftpClient,final String fileName) {
		boolean flag = false ;
		try {
			FTPFile[] ftpFiles = ftpClient.listFiles(null, new FTPFileFilter() {
				@Override
				public boolean accept(FTPFile file) {
					if(file.getName().equals(fileName)){
						return true ;
					}
					return false ;
				}
			}) ;
			
			if(ftpFiles!=null&&ftpFiles.length>0){
				flag = true ;
			}
		} catch (Exception e) {
			System.out.println("-------query ftp file exist fail......");
		}
		
		return flag ;
	}
       @Override
	public boolean isExist(String directory, final String fileName) {
		boolean flag = false ;
		FTPClient ftpClient = null ;
		try {
			ftpClient = getFtpClient(directory) ;
			
			FTPFile[] ftpFiles = ftpClient.listFiles(null, new FTPFileFilter() {
				@Override
				public boolean accept(FTPFile file) {
					if(file.getName().equals(fileName)){
						return true ;
					}
					return false ;
				}
			}) ;
			
			if(ftpFiles!=null&&ftpFiles.length>0){
				flag = true ;
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
	        close(ftpClient); 
		}
		
		return flag ;
	}
}
注:使用FTP上传文件时,在有的机器上会停留在storeFile方法上不动,没有反应。解决:需要设置FTP数据连接模式为被动模式,即在获取FTP连接后设置ftpclient.enterLocalPassiveMode()。原因是:FTP协议有两种工作方式:PORT方式和PASV方式,中文意思为主动式和被动式。 PORT(主动)方式的连接过程是:客户端向服务器的FTP端口(默认是21)发送连接请 求,服务器接受连接,建立一条命令链路。当需要传送数据时,客户端在命令链路上用PORT 命令告诉服务器:“我打开了XXXX端口,你过来连接我”。于是服务器从20端口向客户端的 XXXX端口发送连接请求,建立一条数据链路来传送数据。 PASV(被动)方式的连接过程是:客户端向服务器的FTP端口(默认是21)发送连接请 求,服务器接受连接,建立一条命令链路。当需要传送数据时,服务器在命令链路上用PASV 命令告诉客户端:“我打开了XXXX端口,你过来连接我”。于是客户端向服务器的XXXX端口 发送连接请求,建立一条数据链路来传送数据。被动模式不需要关注客户端配置情况,只需要关注FTP服务器即可。FTP数据连接模式默认为本地主动模式,停留在storeFile方法上有可能是因为本地机器的某个端口被占用,所以没法传数据。
2.Linux下SFtp协议

在Linux使用vsftp安装和配置文件服务器,经测试和使用比较稳定。Linux下配置vsftp参考:http://jingyan.baidu.com/article/adc815133476bdf723bf7393.html

在Linux系统下使用SFTP协议传输文件,相比较FTP,SFTP协议对传输的文件进行了加密,使传输过程更加安全,但是由于使用了加密,传输速度要比FTP的传输速度慢。

JAR包:使用JSCH(Java Sercure Channel),JSCH是一个纯粹的用java实现SSH功能的java  library。Maven依赖如下:

<dependency>
		    <groupId>com.jcraft</groupId>
		    <artifactId>jsch</artifactId>
		    <version>0.1.51</version>
		</dependency>
 文件上传模板类实现:
public class FileManageDaoImplBySFTP extends FileManageDaoTemplate {
    /**
     * 获取连接通道
     * @return
     * @throws JSchException
     */
    public ChannelSftp getChannel() throws JSchException {
        JSch jsch = new JSch(); // 创建JSch对象
        Session session = jsch.getSession(userName, host, port); // 根据用户名,主机ip,端口获取一个Session对象
        if (password != null) {
            session.setPassword(password); // 设置密码
        }
        Properties config = new Properties();
        config.put("StrictHostKeyChecking", "no");
        session.setConfig(config); // 为Session对象设置properties
        session.setTimeout(timeout); // 设置timeout时间
        session.connect(); // 通过Session建立链接
        Channel channel = session.openChannel("sftp"); // 打开SFTP通道
        channel.connect(); // 建立SFTP通道的连接
        return (ChannelSftp) channel;
    }
    /**
     * 关闭连接通道
     * @throws Exception
     */
    public void closeChannel(Channel channel) {
    	if(channel==null){
    		return ;
    	}
    	
    	channel.disconnect();
    	
    	try {
	    	//关闭会话
			if (channel.getSession() != null) {
				channel.getSession().disconnect();
			}
		} catch (JSchException e) {
			e.printStackTrace();
		}
    }
    /**
     * 上传文件到文件服务器
     * @param inputStream
     * @param fileName
     * @throws JSchException 
     */
    @Override
    public void upload(InputStream inputStream,String directory,String fileName) {
		ChannelSftp channelSftp = null;
		try {
			channelSftp = getChannel();
			channelSftp.put(inputStream, targetBaseLocation+directory+fileName);
			channelSftp.quit();
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			closeChannel(channelSftp);
		}
    }
    /**
     * 从文件服务器上下载文件
     */
    @Override
    public void download(OutputStream outputStream,String directory,String fileName){
		ChannelSftp channelSftp = null;
		try {
			channelSftp = getChannel();
			channelSftp.get(targetBaseLocation+directory+fileName, outputStream, null,ChannelSftp.OVERWRITE , 0);
		} catch (Exception e) {
			//TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			closeChannel(channelSftp);
		}
    }
    
    public InputStream getAttachmentFile(String directory,String fileName){
    	return null ;
	}
    
	@Override
	public void delete(String directory,String fileName) {
		ChannelSftp channelSftp = null;
		try {
			channelSftp = getChannel();
			channelSftp.rm(targetBaseLocation+directory+fileName);
		} catch (Exception e) {
			//TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			closeChannel(channelSftp);
		}
	}
       @Override
	public boolean isExist(String directory, String fileName) {
		// TODO Auto-generated method stub
		return false;
	}
}

注:项目框架是Spring,DAO层的类都是使用单例模式,考虑到多线程,在DAO类中不要包括和连接相关的属性,以免一个线程在传输文件过程连接被另一个线程关闭。 

Spring配置文件中配置模板类后,根据文件服务器的系统类型选择不同的传输方式。

<!-- 文件服务器模板方法 -->
	<bean id="fileManageDaoTemplate" class="com.dao.FileManageDaoTemplate" abstract="true">
		<property name="host" value="ip"></property>
		<property name="port" value="port"></property>
		<property name="userName" value="administrator"></property>
		<property name="password" value="password"></property>
		<property name="targetLocation" value="/directory/"></property>
		<property name="timeout" value="60000"></property>
	</bean>
	<!-- linux系统使用sftp保存文件 -->
	<!-- 	<bean class="com.dao.FileManageDaoImplBySFTP" parent="fileManageDaoTemplate"> -->
	<!-- 	</bean> -->
	<bean class="com.dao.FileManageDaoImplByFTP" parent="fileManageDaoTemplate"></bean>

 

显示FTP服务器上的图片文件,方案如下:

1.FTP服务上的图片不能直接通过ftp链接显示,在Controller层的一个方法中根据文件目录和文件名,下载下文件后,再将文件回传回去。简单实现如下:

@RequestMapping(value = "/showImage/{directory}/{filename}.{suffix}")
	public void downloadImage(
			@PathVariable("directory") String directory,
			@PathVariable("filename") String filename,
			@PathVariable("suffix") String suffix,
			HttpServletResponse response) throws Exception {  
		response.setContentType("image/jpeg"); 
		
        attachmentFileService.get(response.getOutputStream(),directory+"/" , filename+"."+suffix) ;
	}

 2.在ftp服务器的目录下搭建一个tomcat服务器,使用ftp上传时,将图片文件放到tomcat服务器下。前台通过访问ftp服务器下的tomcat服务器地址显示图片。

 

 
分享到:
评论

相关推荐

    EverEdit文本编辑工具的FTP/SFTP扩展插件

    SFTP则是基于SSH的安全文件传输协议,它提供了一种加密的通信方式,保证了数据在传输过程中的安全。EverEdit的SFTP插件则进一步增强了安全性,适用于需要保护数据隐私的场景。SFTP插件通常具备与FTP插件相似的功能,...

    Windows平台c++对ftp/sftp文件和文件夹下载上传工程源代码

    在Windows平台上进行FTP(文件传输协议)和SFTP(安全文件传输协议)的文件与文件夹的下载和上传,通常需要使用特定的库来实现。本项目提供的是一套完整的C++工程源代码,包含了FTP和SFTP的客户端功能,便于开发者在...

    Mac版FileZilla - FTP/SFTP客户端软件

    FTP基于TCP/IP协议族,确保了数据传输的可靠性。 **SFTP简介** SFTP(Secure File Transfer Protocol)是SSH(Secure Shell)框架下的一个安全文件传输子协议。与传统FTP相比,SFTP提供了加密的数据传输,从而保护...

    Mac上最好用的FTP/SFTP工具 Transmit 5.8.2

    FTP是用于在互联网上传输文件的标准协议,而SFTP则是基于SSH的安全文件传输协议,提供了加密的文件传输,确保了数据的安全性。 Transmit 5.8.2是该软件的最新版本,其主要特点和功能包括: 1. **用户界面**:...

    Atom-remote-ftp,atom.io的ftp/ftps/sftp客户端。为icetee/remote提供帮助.zip

    FTPS 和 SFTP 尤其注重数据传输的安全性,通过加密连接保护文件不被窃取或篡改。 安装 Atom Remote FTP 插件后,用户可以在 Atom 中直接配置 FTP 服务器的连接信息,如主机名、端口号、用户名、密码和认证方式等。...

    Qt下基于QFtp/libssh2的ftp/stfp下载客户端源码

    在本项目中,“Qt下基于QFtp/libssh2的ftp/stfp下载客户端源码”是一个利用Qt库和libssh2库实现的FTP及SFTP下载客户端,具有断点续传和文件存在性检查功能,并且具备进度条显示。 首先,我们要了解QFtp是Qt库中的一...

    【kettle012】kettle访问FTP服务器文件并处理数据至PostgreSQL

    FTP(File Transfer Protocol)是一种广泛使用的网络协议,用于在计算机之间传输文件。在Kettle中,可以使用“FTP”或“SFTP”步骤来连接到FTP服务器。配置包括服务器地址、端口号、用户名、密码和工作目录等信息。...

    FTP与SFTP文件上传Demo

    FtpDemo可能包含了一个或多个程序,这些程序演示了如何使用编程语言(如Java、Python、C#等)连接到FTP或SFTP服务器,并执行文件上传操作。这些示例可能涵盖了以下知识点: 1. FTP连接:创建FTPClient对象,设置...

    FTP服务器单文件绿色版FTPServer

    FTP服务器是一种用于在互联网上进行文件传输的服务,它允许用户从一台计算机(客户端)向另一台计算机(服务器)上传或下载文件。FTP(File Transfer Protocol)是这项服务的基础协议,它是一个标准网络协议,用于在...

    FTP,SFTP,FTPS总结

    SFTP(Secure File Transfer Protocol,安全文件传输协议)是一种基于 SSH 协议的文件传输协议。它提供了加密的文件传输功能,能够保护文件传输过程中的数据安全。 SFTP 的主要特点是: 1. 基于 SSH 协议 2. 提供...

    基于Python实现FTP文件上传与下载操作(FTP&SFTP协议)

    然而,FTP协议本身并不提供加密功能,数据传输可能存在安全风险。为了解决这个问题,SFTP(Secure File Transfer Protocol)应运而生,它是基于SSH(Secure Shell)的一种安全文件传输协议,能确保数据在传输过程中...

    SFTP.rar_FTP CLIENT_sftp_sftp client_文件 传输_文件传输

    在IT行业中,文件传输是日常工作中非常常见的一种操作,尤其在网络通信中,FTP(File Transfer Protocol)和SFTP(Secure File Transfer Protocol)是两种广泛使用的协议。本篇将重点介绍FTP客户端的实现以及SFTP的...

    强大的SFTP FTP搜索引擎

    SFTP,全称Secure File Transfer Protocol,是FTP的一个安全版本,它通过加密连接保护数据传输过程中的安全性,防止数据被窃取或篡改。SFTP不仅具备FTP的功能,还提供了额外的安全保障,如SSH(Secure Shell)加密,...

    FTP协议的文件传输服务器

    在这个场景中,我们讨论的是一个由外国人编写的基于FTP的文件传输服务器程序,这可能是一个开源或商业软件,为用户提供稳定、高效的文件共享服务。 FTP协议的基础知识包括以下几个关键点: 1. **用户认证**:FTP...

    windows脚本SFTP上传文件至备份服务器方案

    ### Windows脚本SFTP上传文件至备份服务器方案 #### 概述 在当前的信息安全环境中,数据备份成为了保障业务连续性和数据...通过本方案,可以有效地实现文件的自动备份和安全传输,提高了数据传输的安全性和可靠性。

    WinSCP 是一个用于 Windows 的开源 SFTP(SSH 文件传输协议)、FTP(文件传输协议)、

    文件传输:支持 SFTP、FTP、WebDAV 和 SCP 协议,可以在本地计算机和远程服务器之间进行文件传输。 图形用户界面(GUI):提供用户友好的图形界面,支持拖放操作,使文件传输和管理更加方便。 文件同步:可以同步...

    FTP,SFTP文件上传,下载到服务器,ZIP文件压缩,加密,解密,然后再上传到服务器,各种封装操作;

    相比FTP,SFTP提供了加密的数据传输,确保了文件在传输过程中的安全,防止数据被窃取或篡改。SFTP常用于对安全性要求较高的环境。 文件压缩,如ZIP格式,是一种常见的文件归档方法。ZIP可以将多个文件或目录打包成...

    C++ 简单的Ftp文件传输

    在IT领域,FTP(File Transfer Protocol)是一种广泛用于在互联网上传输文件的协议。这个“C++简单的FTP文件传输”项目旨在为初学者提供一个学习基础FTP文件传输原理的平台。通过这个项目,你可以了解如何使用C++...

    基于FTP协议的C/S代码

    FTP(File Transfer Protocol)协议是互联网上用于在不同主机之间传输文件的标准协议,它基于TCP/IP协议栈。在这个“基于FTP协议的C/S代码”项目中,开发者构建了一个简单的客户端/服务器(C/S)架构的程序,旨在...

Global site tag (gtag.js) - Google Analytics