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

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

vsftp简介

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

CentOS6.5安装vsftp

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

1.检测是否安装了vsftp

[root@dev04 ~]# rpm -qa |grep vsftpd
vsftpd-2.2.2-14.el6.x86_64
我是安装过的, 命令下方返回的是我的vsftp版本

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

rpm -e vsftpd
再执行
rpm -qa |grep vsftpd
查看卸载是否成功,如果成功会返回卸载的vsftp的版本

2.安装vsftp

yum install vsftpd* -y

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

chkconfig vsftpd on

4.启动ftp服务

[root@dev04 vsftpd]# service vsftpd start
关闭服务:
[root@dev04 vsftpd]# service vsftpd stop
重启服务:
[root@dev04 vsftpd]# service vsftpd restart

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

在 /etc/vsftpd目录下有三个文件和一个执行命令?
-rw------- 1 root root  125 Jul 24  2015 ftpusers
-rw------- 1 root root  371 Apr  6 14:11 user_list
-rw------- 1 root root 4737 Apr  1 15:51 vsftpd.conf
-rwxr--r-- 1 root root  338 Jul 24  2015 vsftpd_conf_migrate.sh
要修改的配置信息都在vsftpd.conf配置文件中,修改配置文件之前最好进行备份
[root@dev04 vsftpd]# cp vsftpd.conf vsftpd.conf.bak

再进行编辑修改配置文件
[root@dev04 vsftpd]# vim /etc/vsftpd/vsftpd.conf

主要的就是匿名用户的访问权限和 新增本地用户设置访问权限
因为要提供给终端使用FTP服务器映射的公网进行访问,又不行暴露服务器文件所在的目录,
必须支持匿名用户的访问, ftp匿名用户默认目录为 /var/ftp/pub目录下
vsftpd.conf配置文件主要修改
anonymous_enable=YES   // 支持匿名登录,如果改为NO不支持匿名登录
write_enable=YES	//支持读
anon_upload_enable=YES	//支持匿名改写
anon_mkdir_write_enable=YES	//支持匿名用户创建子目录

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

useradd -d /home/ftpuser -g ftp -s /sbin/nologin ftpuser
给帐号设置密码
passwd ftpuer
注意: 在设置密码时会提示什么密码过于简单,或者密码为单词词组等等,不用管,它已经进行设置了,要确认两次输入的密码都相同;输入两次密码后出现successful.....就代表设置密码成功了;
创建用户时遇到的问题:
1.我开始是关闭匿名用户的登录权限的,设置了ftpuser, 终端访问时必须要输入 ftp://username:password@IP地址:port/访问路径   这样会暴露文件存放的路径,不合理(我觉得可能是我设置ftpuser用户时没有在配置文件中配置默认目录什么的,因为按照前面这样访问时候默认进入默认目录/ftpuser的,这点没怎么清楚==)
2.项目中上传文件原本是使用fastDFS文件服务器的,现在改为FTP,将固件上传到匿名用户目录下,提供终端下载
新建了anon用户将默认目录设置为匿名访问的目录 /var/ftp/pub

useradd -d /var/ftp -g ftp -s /sbin/nologin anon
在使用java进行上传文件时发现anon用户不能连接上该目录,查资料说是没有对目录进行设置权限

注意的事项是的:

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文件

<!-- https://mvnrepository.com/artifact/commons-net/commons-net -->
	<dependency>
		<groupId>commons-net</groupId>
		<artifactId>commons-net</artifactId>
		<version>3.6</version>
	</dependency>

2.ftp配置文件 ftp_client.properties

#公网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类,提高代码扩展性

@Component
public class FTPConfig {

    /** FTP服务器IP地址 */
    @Value("#{configProperties['ftp_host']}")
    private String fTPhost = "localhost";

    /** FTP服务器端口 */
    @Value("#{configProperties['ftp_port']}")
    private int ftpPort = 21;

    /** FTP服务器用户名 */
    @Value("#{configProperties['ftp_user_name']}")
    private String ftpUserName;

    /** FTP用户密码 */
    @Value("#{configProperties['ftp_user_pwd']}")
    private String ftpUserPasswd;

    /** 用户远程上传文件存储目录 */
    @Value("#{configProperties['remoteFile_addr']}")
    private String remoteFileAddr;

    /** FTP公网映射地址 */
    @Value("#{configProperties['ftp_public_network_add']}")
    private String ftpNetAdd;

    /** FTP公网端口 */
    @Value("#{configProperties['ftp_public_network_port']}")
    private int ftpNetPort = 2121;
}

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

/**
 * @Type ftpClientFileManager.java
 * @Desc 
 * @author 123
 * @date 2017年3月31日 下午2:50:58
 * @version 
 */
@Service
public class FTPFileManager {

    private static final Logger logger = LoggerFactory.getLogger(FTPFileManager.class);

    private FTPClient ftpClient = new FTPClient();

    /** 路径分隔符 */
    private static final String SEPARATOR = "/";

    /** FTP访问路径前缀 */
    private static final String FTP_PREFIX = "ftp://";

    @Autowired
    private FTPConfig config;

    /**
     * @Title: upload 
     *
     * @Description: 文件上传
     *
     * @param uploadFile
     *          MultipartFile
     * @return
     *          返回保存路径 + 文件名
     * @throws Exception 
     *
     */
    public String upload(MultipartFile uploadFile) throws Exception {

        ftpClient = new FTPClient();
        ftpClient.connect(config.getfTPhost(), config.getFtpPort());

        ftpClient.login(config.getFtpUserName(), config.getFtpUserPasswd());
        //设置ftp字节流
        ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
        int reply;
        reply = ftpClient.getReplyCode();
        if (!FTPReply.isPositiveCompletion(reply)) {
            ftpClient.disconnect();
            return null;
        }
        ftpClient.enterLocalPassiveMode();
        String basePath = config.getRemoteFileAddr();
        ftpClient.changeWorkingDirectory(basePath);

        //为当天日期文件创建追加目录
        Date today = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
        String appendFile = sdf.format(today);
        //切换到上传目录
        if (!ftpClient.changeWorkingDirectory(basePath + appendFile)) {
            //如果目录不存在创建目录
            String[] dirs = appendFile.split(SEPARATOR);
            String tempTargetPath = basePath;
            for (String dir : dirs) {
                if (null == dir || "".equals(dir))
                    continue;
                tempTargetPath += SEPARATOR + dir;
                if (!ftpClient.changeWorkingDirectory(tempTargetPath)) {
                    if (!ftpClient.makeDirectory(tempTargetPath)) {
                        logger.error("ftp文件目录创建失败!");
                        return null;
                    } else {
                        ftpClient.changeWorkingDirectory(tempTargetPath);
                    }
                }
            }
        }

        String fileName = new String(uploadFile.getOriginalFilename().getBytes("utf-8"),
                "iso-8859-1");
        /**
         * 避免文件过多后出现重名,设置30位随机数为文件名称
         */
        // 获取文件扩展名 形如: .txt
        String fileExt = fileName.substring(fileName.lastIndexOf("."));
        String newFileName = RandomUtils.randomAlphanumericStrictly(30) + fileExt;

        InputStream is = uploadFile.getInputStream();
        if (!ftpClient.storeFile(newFileName, is)) {
            logger.error("文件{}存储过程出错", fileName);
            return null;
        }
        is.close();
        ftpClient.disconnect();
        /* String finalFile = basePath + SEPARATOR + appendFile + SEPARATOR + fileName;*/
        //直接存储为匿名用户可直接访问下载的地址
        String finalFile = FTP_PREFIX + config.getFtpNetAdd() + ":" + config.getFtpNetPort()
                + SEPARATOR + "pub" + SEPARATOR + appendFile + SEPARATOR + newFileName;
        logger.info("文件上传FTP服务器成功, 访问文件路径为 : " + finalFile);
        return finalFile;
    }

    /** 
     * 从FTP服务器上下载文件 
     * @param remote 远程文件路径 
     * @param local 本地文件路径 
     * @return 是否成功 
     * @throws Exception 
     */
    public boolean download(String remote, String local) throws Exception {
        ftpClient = new FTPClient();
        ftpClient.connect(config.getfTPhost(), config.getFtpPort());
        ftpClient.login(config.getFtpUserName(), config.getFtpUserPasswd());
        ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
        int reply;
        reply = ftpClient.getReplyCode();
        if (!FTPReply.isPositiveCompletion(reply)) {
            ftpClient.disconnect();
            return false;
        }

        ftpClient.enterLocalPassiveMode();
        ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
        boolean result;
        File f = new File(local);
        FTPFile[] files = ftpClient.listFiles(remote);
        if (files.length != 1) {
            System.out.println("远程文件不唯一");
            ftpClient.disconnect();
            return false;
        }
        long lRemoteSize = files[0].getSize();
        if (f.exists()) {
            OutputStream out = new FileOutputStream(f, true);
            System.out.println("本地文件大小为:" + f.length());
            if (f.length() >= lRemoteSize) {
                logger.error("本地文件大小大于远程文件大小,下载中止");
                out.close();
                ftpClient.disconnect();
                return false;
            }
            ftpClient.setRestartOffset(f.length());
            result = ftpClient.retrieveFile(remote, out);
            out.close();
        } else {
            OutputStream out = new FileOutputStream(f);
            result = ftpClient.retrieveFile(remote, out);
            out.close();
        }
        ftpClient.disconnect();
        return result;
    }

}

/**
 * Revision history
 * -------------------------------------------------------------------------
 * 
 * Date Author Note
 * -------------------------------------------------------------------------
 * 2017年3月31日 123 creat
 */


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



简单的记录.

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
支持断点续传的上传方法
/** 
     * 上传文件到FTP服务器,支持断点续传 
     * @param local 本地文件名称,绝对路径 
     * @param remote 远程文件路径,使用/home/directory1/subdirectory/file.ext 按照Linux上的路径指定方式,支持多级目录嵌套,支持递归创建不存在的目录结构 
     * @return 上传结果 
     * @throws IOException 
     */
    public String upload(String local, String remote) throws IOException {
        //设置PassiveMode传输  
        ftpClient.enterLocalPassiveMode();
        //设置以二进制流的方式传输  
        ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
        String uploadStatus;
        //对远程目录的处理  
        String remoteFileName = remote;
        if (remote.contains("/")) {
            remoteFileName = remote.substring(remote.lastIndexOf("/") + 1);
            String directory = remote.substring(0, remote.lastIndexOf("/") + 1);
            if (!directory.equalsIgnoreCase("/") && !ftpClient.changeWorkingDirectory(directory)) {
                //如果远程目录不存在,则递归创建远程服务器目录  
                int start = 0;
                int end = 0;
                if (directory.startsWith("/")) {
                    start = 1;
                } else {
                    start = 0;
                }
                end = directory.indexOf("/", start);
                while (true) {
                    String subDirectory = remote.substring(start, end);
                    if (!ftpClient.changeWorkingDirectory(subDirectory)) {
                        if (ftpClient.makeDirectory(subDirectory)) {
                            ftpClient.changeWorkingDirectory(subDirectory);
                        } else {
                            System.out.println("创建目录失败");
                            return UploadStatus.Create_Directory_Fail;
                        }
                    }

                    start = end + 1;
                    end = directory.indexOf("/", start);

                    //检查所有目录是否创建完毕  
                    if (end <= start) {
                        break;
                    }
                }
            }
        }

        //检查远程是否存在文件  
        FTPFile[] files = ftpClient.listFiles(remoteFileName);
        if (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;
            }

            //尝试移动文件内读取指针,实现断点续传  
            InputStream is = new FileInputStream(f);
            if (is.skip(remoteSize) == remoteSize) {
                //设置文件开始
                ftpClient.setRestartOffset(remoteSize);
                if (ftpClient.storeFile(remote, is)) {
                    is.close();
                    return UploadStatus.Upload_From_Break_Success;
                }

            }

            //如果断点续传没有成功,则删除服务器上文件,重新上传  
            if (!ftpClient.deleteFile(remoteFileName)) {
                return UploadStatus.Delete_Remote_Faild;
            }
            is = new FileInputStream(f);
            if (ftpClient.storeFile(remote, is)) {
                uploadStatus = UploadStatus.Upload_New_File_Success;
            } else {
                uploadStatus = UploadStatus.Upload_New_File_Failed;
            }
            is.close();
        } else {
            InputStream is = new FileInputStream(local);
            if (ftpClient.storeFile(remoteFileName, is)) {
                uploadStatus = UploadStatus.Upload_New_File_Success;
            } else {
                uploadStatus = UploadStatus.Upload_New_File_Failed;
            }
            is.close();
        }
        return uploadStatus;
    }












  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值