CentOS6.5下搭建FTP服务器 + Java上传文件

2018/02/08 15:59
阅读数 217

项目中开始使用http协议进行传输文件,但是终端提出传输的字节超过限度,要使用FTP文件服务器进行断点续传,每次1k的进行传输. 老大让我在开发环境中搭建vsftp服务器,一起没操作过,现在记录下来留做以后的回顾学习;

vsftp简介

vsftpd是一款在Linux发行版中最受推崇的FTP服务器程序。特点是小巧轻快,安全易用。ftp作为文件服务器,断点续传是和http传输的一个区别;

CentOS6.5安装vsftp

以管理员(root)身份进行一下操作:

1.检测是否安装了vsftp

[html] view plain copy

  1. [root@dev04 ~]# rpm -qa |grep vsftpd  
  2. vsftpd-2.2.2-14.el6.x86_64  

我是安装过的, 命令下方返回的是我的vsftp版本

检测到安装过后如果想卸载执行:

[html] view plain copy

  1. rpm -e vsftpd  

再执行[html] view plain copy

  1. rpm -qa |grep vsftpd  

查看卸载是否成功,如果成功会返回卸载的vsftp的版本

2.安装vsftp

[html] view plain copy

  1. yum install vsftpd* -y  

3.设置开机自启vsftp ftp服务

[html] view plain copy

  1. chkconfig vsftpd on  

4.启动ftp服务

[html] view plain copy

  1. [root@dev04 vsftpd]# service vsftpd start  

关闭服务:[html] view plain copy

  1. [root@dev04 vsftpd]# service vsftpd stop  

重启服务:
[html] view plain copy

  1. [root@dev04 vsftpd]# service vsftpd restart  

 

5.配置vsftp的配置文件vsftpd.conf

在 /etc/vsftpd目录下有三个文件和一个执行命令?[html] view plain copy

  1. -rw------- 1 root root  125 Jul 24  2015 ftpusers  
  2. -rw------- 1 root root  371 Apr  6 14:11 user_list  
  3. -rw------- 1 root root 4737 Apr  1 15:51 vsftpd.conf  
  4. -rwxr--r-- 1 root root  338 Jul 24  2015 vsftpd_conf_migrate.sh  

要修改的配置信息都在vsftpd.conf配置文件中,修改配置文件之前最好进行备份

[html] view plain copy

  1. [root@dev04 vsftpd]# cp vsftpd.conf vsftpd.conf.bak  


再进行编辑修改配置文件[html] view plain copy

  1. [root@dev04 vsftpd]# vim /etc/vsftpd/vsftpd.conf  

 

主要的就是匿名用户的访问权限和 新增本地用户设置访问权限

因为要提供给终端使用FTP服务器映射的公网进行访问,又不行暴露服务器文件所在的目录,

必须支持匿名用户的访问, ftp匿名用户默认目录为 /var/ftp/pub目录下

vsftpd.conf配置文件主要修改

[html] view plain copy

  1. anonymous_enable=YES   // 支持匿名登录,如果改为NO不支持匿名登录  

[html] view plain copy

  1. write_enable=YES<span style="white-space:pre;"> </span>//支持读  

[html] view plain copy

  1. anon_upload_enable=YES<span style="white-space:pre;">   </span>//支持匿名改写  

[html] view plain copy

  1. anon_mkdir_write_enable=YES<span style="white-space:pre;">  </span>//支持匿名用户创建子目录  

 

6.创建用户ftpuser,指定目录/home/ftpuser,禁止SSH登录权限

[html] view plain copy

  1. useradd -d /home/ftpuser -g ftp -s /sbin/nologin ftpuser  

给帐号设置密码[html] view plain copy

  1. passwd ftpuer  

注意: 在设置密码时会提示什么密码过于简单,或者密码为单词词组等等,不用管,它已经进行设置了,要确认两次输入的密码都相同;输入两次密码后出现successful.....就代表设置密码成功了;

创建用户时遇到的问题:

1.我开始是关闭匿名用户的登录权限的,设置了ftpuser, 终端访问时必须要输入 ftp://username:password@IP地址:port/访问路径   这样会暴露文件存放的路径,不合理(我觉得可能是我设置ftpuser用户时没有在配置文件中配置默认目录什么的,因为按照前面这样访问时候默认进入默认目录/ftpuser的,这点没怎么清楚==)

2.项目中上传文件原本是使用fastDFS文件服务器的,现在改为FTP,将固件上传到匿名用户目录下,提供终端下载

新建了anon用户将默认目录设置为匿名访问的目录 /var/ftp/pub

 

[html] view plain copy

  1. useradd -d /var/ftp -g ftp -s /sbin/nologin anon  

在使用java进行上传文件时发现anon用户不能连接上该目录,查资料说是没有对目录进行设置权限

LINUX下搭建FTP服务器--非宁静无以致远

注意的事项是的:

1、pub目录的权限不能全开,全开会报错,chmod 755 -R pub

2、但是这样也会带来一个问题,当匿名用户登录后,在pub下的newftp目录下想上传一个文件,会报错,因为匿名用户(ftp)无法在该目录下(该目录属于root用户)创建一个新文件的,因为该目录下他没有权限,所以要加入其他用户(o)的写权限,chmod o+w /var/ftp/pub/.

现在权限变为:
drwxr-xrwx 2 root root   4096 06-20 16:55 pub
其实就是757的权限,此时匿名用户(ftp)就可以在该目录下上传文件了。

 

最后重启服务: service vsftpd restart

 

附上MultipartFile使用ftp上传文件

1.maven项目中添加pom文件

[html] view plain copy

  1. <!-- https://mvnrepository.com/artifact/commons-net/commons-net -->  
  2.     <dependency>  
  3.         <groupId>commons-net</groupId>  
  4.         <artifactId>commons-net</artifactId>  
  5.         <version>3.6</version>  
  6.     </dependency>  

 

2.ftp配置文件 ftp_client.properties

[html] view plain copy

  1.   

#公网IP映射地址: 218.205.115.XXX 2121

ftp_public_network_add = 218.205.115.XXX #FTP公网端口 ftp_public_network_port = 2121 #FTP服务器地址172.23.28.XXX ftp_host = 172.23.28.XXX #21 ftp_port = 21 ##匿名用户 anonymous 创建一个用户名为ftpuser,目录在pub下,具有增删改查/新建子目录权限 ftp_user_name = ftpuser ftp_user_pwd = ftpuser #匿名登录上传目录 /var/ftp/pub remoteFile_addr = /var/ftp/pub/

3.自定义配置文件的pojo类,提高代码扩展性

[java] view plain copy

  1. @Component  
  2. public class FTPConfig {  
  3.   
  4.     /** FTP服务器IP地址 */  
  5.     @Value("#{configProperties['ftp_host']}")  
  6.     private String fTPhost = "localhost";  
  7.   
  8.     /** FTP服务器端口 */  
  9.     @Value("#{configProperties['ftp_port']}")  
  10.     private int ftpPort = 21;  
  11.   
  12.     /** FTP服务器用户名 */  
  13.     @Value("#{configProperties['ftp_user_name']}")  
  14.     private String ftpUserName;  
  15.   
  16.     /** FTP用户密码 */  
  17.     @Value("#{configProperties['ftp_user_pwd']}")  
  18.     private String ftpUserPasswd;  
  19.   
  20.     /** 用户远程上传文件存储目录 */  
  21.     @Value("#{configProperties['remoteFile_addr']}")  
  22.     private String remoteFileAddr;  
  23.   
  24.     /** FTP公网映射地址 */  
  25.     @Value("#{configProperties['ftp_public_network_add']}")  
  26.     private String ftpNetAdd;  
  27.   
  28.     /** FTP公网端口 */  
  29.     @Value("#{configProperties['ftp_public_network_port']}")  
  30.     private int ftpNetPort = 2121;  

[java] view plain copy

  1. }  

4.FTP上传下载的工具类FTPFileManager

[java] view plain copy

  1. /** 
  2.  * @Type ftpClientFileManager.java 
  3.  * @Desc  
  4.  * @author 123 
  5.  * @date 2017年3月31日 下午2:50:58 
  6.  * @version  
  7.  */  
  8. @Service  
  9. public class FTPFileManager {  
  10.   
  11.     private static final Logger logger = LoggerFactory.getLogger(FTPFileManager.class);  
  12.   
  13.     private FTPClient ftpClient = new FTPClient();  
  14.   
  15.     /** 路径分隔符 */  
  16.     private static final String SEPARATOR = "/";  
  17.   
  18.     /** FTP访问路径前缀 */  
  19.     private static final String FTP_PREFIX = "ftp://";  
  20.   
  21.     @Autowired  
  22.     private FTPConfig config;  
  23.   
  24.     /** 
  25.      * @Title: upload  
  26.      * 
  27.      * @Description: 文件上传 
  28.      * 
  29.      * @param uploadFile 
  30.      *          MultipartFile 
  31.      * @return 
  32.      *          返回保存路径 + 文件名 
  33.      * @throws Exception  
  34.      * 
  35.      */  
  36.     public String upload(MultipartFile uploadFile) throws Exception {  
  37.   
  38.         ftpClient = new FTPClient();  
  39.         ftpClient.connect(config.getfTPhost(), config.getFtpPort());  
  40.   
  41.         ftpClient.login(config.getFtpUserName(), config.getFtpUserPasswd());  
  42.         //设置ftp字节流  
  43.         ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);  
  44.         int reply;  
  45.         reply = ftpClient.getReplyCode();  
  46.         if (!FTPReply.isPositiveCompletion(reply)) {  
  47.             ftpClient.disconnect();  
  48.             return null;  
  49.         }  
  50.         ftpClient.enterLocalPassiveMode();  
  51.         String basePath = config.getRemoteFileAddr();  
  52.         ftpClient.changeWorkingDirectory(basePath);  
  53.   
  54.         //为当天日期文件创建追加目录  
  55.         Date today = new Date();  
  56.         SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");  
  57.         String appendFile = sdf.format(today);  
  58.         //切换到上传目录  
  59.         if (!ftpClient.changeWorkingDirectory(basePath + appendFile)) {  
  60.             //如果目录不存在创建目录  
  61.             String[] dirs = appendFile.split(SEPARATOR);  
  62.             String tempTargetPath = basePath;  
  63.             for (String dir : dirs) {  
  64.                 if (null == dir || "".equals(dir))  
  65.                     continue;  
  66.                 tempTargetPath += SEPARATOR + dir;  
  67.                 if (!ftpClient.changeWorkingDirectory(tempTargetPath)) {  
  68.                     if (!ftpClient.makeDirectory(tempTargetPath)) {  
  69.                         logger.error("ftp文件目录创建失败!");  
  70.                         return null;  
  71.                     } else {  
  72.                         ftpClient.changeWorkingDirectory(tempTargetPath);  
  73.                     }  
  74.                 }  
  75.             }  
  76.         }  
  77.   
  78.         String fileName = new String(uploadFile.getOriginalFilename().getBytes("utf-8"),  
  79.                 "iso-8859-1");  
  80.         /** 
  81.          * 避免文件过多后出现重名,设置30位随机数为文件名称 
  82.          */  
  83.         // 获取文件扩展名 形如: .txt  
  84.         String fileExt = fileName.substring(fileName.lastIndexOf("."));  
  85.         String newFileName = RandomUtils.randomAlphanumericStrictly(30) + fileExt;  
  86.   
  87.         InputStream is = uploadFile.getInputStream();  
  88.         if (!ftpClient.storeFile(newFileName, is)) {  
  89.             logger.error("文件{}存储过程出错", fileName);  
  90.             return null;  
  91.         }  
  92.         is.close();  
  93.         ftpClient.disconnect();  
  94.         /* String finalFile = basePath + SEPARATOR + appendFile + SEPARATOR + fileName;*/  
  95.         //直接存储为匿名用户可直接访问下载的地址  
  96.         String finalFile = FTP_PREFIX + config.getFtpNetAdd() + ":" + config.getFtpNetPort()  
  97.                 + SEPARATOR + "pub" + SEPARATOR + appendFile + SEPARATOR + newFileName;  
  98.         logger.info("文件上传FTP服务器成功, 访问文件路径为 : " + finalFile);  
  99.         return finalFile;  
  100.     }  
  101.   
  102.     /**  
  103.      * 从FTP服务器上下载文件  
  104.      * @param remote 远程文件路径  
  105.      * @param local 本地文件路径  
  106.      * @return 是否成功  
  107.      * @throws Exception  
  108.      */  
  109.     public boolean download(String remote, String local) throws Exception {  
  110.         ftpClient = new FTPClient();  
  111.         ftpClient.connect(config.getfTPhost(), config.getFtpPort());  
  112.         ftpClient.login(config.getFtpUserName(), config.getFtpUserPasswd());  
  113.         ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);  
  114.         int reply;  
  115.         reply = ftpClient.getReplyCode();  
  116.         if (!FTPReply.isPositiveCompletion(reply)) {  
  117.             ftpClient.disconnect();  
  118.             return false;  
  119.         }  
  120.   
  121.         ftpClient.enterLocalPassiveMode();  
  122.         ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);  
  123.         boolean result;  
  124.         File f = new File(local);  
  125.         FTPFile[] files = ftpClient.listFiles(remote);  
  126.         if (files.length != 1) {  
  127.             System.out.println("远程文件不唯一");  
  128.             ftpClient.disconnect();  
  129.             return false;  
  130.         }  
  131.         long lRemoteSize = files[0].getSize();  
  132.         if (f.exists()) {  
  133.             OutputStream out = new FileOutputStream(f, true);  
  134.             System.out.println("本地文件大小为:" + f.length());  
  135.             if (f.length() >= lRemoteSize) {  
  136.                 logger.error("本地文件大小大于远程文件大小,下载中止");  
  137.                 out.close();  
  138.                 ftpClient.disconnect();  
  139.                 return false;  
  140.             }  
  141.             ftpClient.setRestartOffset(f.length());  
  142.             result = ftpClient.retrieveFile(remote, out);  
  143.             out.close();  
  144.         } else {  
  145.             OutputStream out = new FileOutputStream(f);  
  146.             result = ftpClient.retrieveFile(remote, out);  
  147.             out.close();  
  148.         }  
  149.         ftpClient.disconnect();  
  150.         return result;  
  151.     }  
  152.   
  153. }  
  154.   
  155. /** 
  156.  * Revision history 
  157.  * ------------------------------------------------------------------------- 
  158.  *  
  159.  * Date Author Note 
  160.  * ------------------------------------------------------------------------- 
  161.  * 2017年3月31日 123 creat 
  162.  */  

 

 

此时,用户可以通过公网映射的IP进行访问, 类似 ftp://218.205.115.XXXX:2121/pub/2017/04/06/4cn91c2dRffmQ8diQ4mvDRo5m2lWtr.txt
由于项目中没使用到文件下载,我只在本地进行了简单的下载centOS中FTP文件测试.

 

简单的记录.


+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
支持断点续传的上传方法
[java] view plain copy

  1. /**  
  2.      * 上传文件到FTP服务器,支持断点续传  
  3.      * @param local 本地文件名称,绝对路径  
  4.      * @param remote 远程文件路径,使用/home/directory1/subdirectory/file.ext 按照Linux上的路径指定方式,支持多级目录嵌套,支持递归创建不存在的目录结构  
  5.      * @return 上传结果  
  6.      * @throws IOException  
  7.      */  
  8.     public String upload(String local, String remote) throws IOException {  
  9.         //设置PassiveMode传输    
  10.         ftpClient.enterLocalPassiveMode();  
  11.         //设置以二进制流的方式传输    
  12.         ftpClient.setFileType(FTP.BINARY_FILE_TYPE);  
  13.         String uploadStatus;  
  14.         //对远程目录的处理    
  15.         String remoteFileName = remote;  
  16.         if (remote.contains("/")) {  
  17.             remoteFileName = remote.substring(remote.lastIndexOf("/") + 1);  
  18.             String directory = remote.substring(0, remote.lastIndexOf("/") + 1);  
  19.             if (!directory.equalsIgnoreCase("/") && !ftpClient.changeWorkingDirectory(directory)) {  
  20.                 //如果远程目录不存在,则递归创建远程服务器目录    
  21.                 int start = 0;  
  22.                 int end = 0;  
  23.                 if (directory.startsWith("/")) {  
  24.                     start = 1;  
  25.                 } else {  
  26.                     start = 0;  
  27.                 }  
  28.                 end = directory.indexOf("/", start);  
  29.                 while (true) {  
  30.                     String subDirectory = remote.substring(start, end);  
  31.                     if (!ftpClient.changeWorkingDirectory(subDirectory)) {  
  32.                         if (ftpClient.makeDirectory(subDirectory)) {  
  33.                             ftpClient.changeWorkingDirectory(subDirectory);  
  34.                         } else {  
  35.                             System.out.println("创建目录失败");  
  36.                             return UploadStatus.Create_Directory_Fail;  
  37.                         }  
  38.                     }  
  39.   
  40.                     start = end + 1;  
  41.                     end = directory.indexOf("/", start);  
  42.   
  43.                     //检查所有目录是否创建完毕    
  44.                     if (end <= start) {  
  45.                         break;  
  46.                     }  
  47.                 }  
  48.             }  
  49.         }  
  50.   
  51.         //检查远程是否存在文件    
  52.         FTPFile[] files = ftpClient.listFiles(remoteFileName);  
  53.         if (files.length == 1) {  
  54.             long remoteSize = files[0].getSize();  
  55.             File f = new File(local);  
  56.             long localSize = f.length();  
  57.             if (remoteSize == localSize) {  
  58.                 return UploadStatus.File_Exits;  
  59.             } else if (remoteSize > localSize) {  
  60.                 return UploadStatus.Remote_Bigger_Local;  
  61.             }  
  62.   
  63.             //尝试移动文件内读取指针,实现断点续传    
  64.             InputStream is = new FileInputStream(f);  
  65.             if (is.skip(remoteSize) == remoteSize) {  
  66.                 //设置文件开始  
  67.                 ftpClient.setRestartOffset(remoteSize);  
  68.                 if (ftpClient.storeFile(remote, is)) {  
  69.                     is.close();  
  70.                     return UploadStatus.Upload_From_Break_Success;  
  71.                 }  
  72.   
  73.             }  
  74.   
  75.             //如果断点续传没有成功,则删除服务器上文件,重新上传    
  76.             if (!ftpClient.deleteFile(remoteFileName)) {  
  77.                 return UploadStatus.Delete_Remote_Faild;  
  78.             }  
  79.             is = new FileInputStream(f);  
  80.             if (ftpClient.storeFile(remote, is)) {  
  81.                 uploadStatus = UploadStatus.Upload_New_File_Success;  
  82.             } else {  
  83.                 uploadStatus = UploadStatus.Upload_New_File_Failed;  
  84.             }  
  85.             is.close();  
  86.         } else {  
  87.             InputStream is = new FileInputStream(local);  
  88.             if (ftpClient.storeFile(remoteFileName, is)) {  
  89.                 uploadStatus = UploadStatus.Upload_New_File_Success;  
  90.             } else {  
  91.                 uploadStatus = UploadStatus.Upload_New_File_Failed;  
  92.             }  
  93.             is.close();  
  94.         }  
  95.         return uploadStatus;  
  96.     }  
展开阅读全文
加载中

作者的其它热门文章

打赏
0
4 收藏
分享
打赏
0 评论
4 收藏
0
分享
返回顶部
顶部