ftp上传下载工具类

目录结构
在这里插入图片描述

application.yml

# 配置ftp服务器信息
ftp:
  # ftp服务器的IP地址
  url: 
  # 默认端口是21
  port: 21
  username: 
  password: 
  # ftp服务器存放文件的路径
  remotePath: /case
  # 本地需要上传的文件的路径
  localDir: D:/test/case/push
  # ftp上文件下载到本地存放的路径
  downDir: D:/test/case/receive
  # ftp下载zip后解压存放的位置
  unzipDir: D:/test/case/unzip

FtpConfig

package com.vxdata.cases.modules.ftp.config;

import lombok.Data;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * @author :mmzsit
 * @description:ftp服务器相关配置信息
 * @date :2018/03/24 14:05
 */
@Component
@Data
public class FtpConfig {
	/**
	 * ftp服务器地址
	 */
	@Value("${ftp.url}")
	private String url;
	
	/**
	 * ftp服务器端口
	 */
	@Value("${ftp.port}")
	private int port;
	
	/**
	 * ftp服务器用户名
	 */
	@Value("${ftp.username}")
	private String username;
	
	/**
	 * ftp服务器密码
	 */
	@Value("${ftp.password}")
	private String password;
	
	/**
	 * ftp服务器存放文件的路径
	 */
	@Value("${ftp.remotePath}")
	private String remotePath;
	
	/**
	 * 本地需要上传的文件的路径
	 */
	@Value("${ftp.localDir}")
	private String localDir;
	
	/**
	 * 下载文件时,存放在本地的路径
	 */
	@Value("${ftp.downDir}")
	private String downDir;

	@Value("${ftp.unzipDir}")
	private String unzipDir;
	
}

FtpUtil

package com.vxdata.cases.modules.ftp.utils;

import com.vxdata.cases.modules.ftp.config.FtpConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.*;
import org.apache.poi.hssf.record.DVALRecord;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.*;
import java.net.SocketException;

@Slf4j(topic="文件上传/下载===ftp服务器:")
@Component
public class FtpUtil {
    private static FTPClient mFTPClient = new FTPClient();
    private static FtpUtil ftp = new FtpUtil();

    private static FtpConfig ftpConfig;

    @Autowired
    public void init(FtpConfig ftpConfig) {
        FtpUtil.ftpConfig = ftpConfig;
    }


    /**
     * 上传文件到ftp服务器
     * @param localPath 本地文件地址
     * @param ftpRemotePath 远程地址
     * @return
     */
    public static boolean ftpUpload(String fileName, String localPath, String ftpRemotePath) {
        boolean result = false;
        try {
            // 链接到ftp服务器
            boolean isConnection = ftp.openConnection();
            if (isConnection) {
                // 上传文件
                boolean isSuccess = ftp.uploadByPath(ftpRemotePath,  fileName);
                if (isSuccess) {
                    log.info("FTP文件上传成功!");
                    result = true;
                } else {
                    log.info("FTP文件上传失败!");
                    result = false;
                }
                // 登出并断开连接
                ftp.logout();
            } else {
                log.info("链接ftp服务器失败,请联系管理员检查配置信息是否正确!");
                result = false;
            }
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 从ftp服务器下载文件到本地
     * @param fileName 要下载的远程文件
     * @param ftpRemotePath 	ftp服务器存放文件的路径
     * @return
     */
    public static boolean ftpDownload(String fileName, String localPath, String ftpRemotePath) {
        boolean result = false;
        try {
            // 连接ftp服务
            boolean isConnection = ftp.openConnection();
            if (isConnection) {
                // 创建远程目录
                boolean isCreateOk = ftp.createDirectory(ftpRemotePath, mFTPClient);
                // 下载文件到本地地址
                boolean isDownloadOk = ftp.downLoad(ftpRemotePath +File.separator+fileName, localPath);
                if (isDownloadOk && isCreateOk) {
                    result = true;
                }
                ftp.logout();
            } else {
                log.info("链接ftp服务器失败,请检查配置信息是否正确!");
                result = false;
            }
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 上传本地文件
     * @param remotePath 远程地址
     * @param localPath 本地文件地址
     * @return
     * @throws IOException
     */
    public boolean uploadByPath(String remotePath, String localPath) throws IOException {
        boolean result = false;
        // 进入被动模式
        mFTPClient.enterLocalPassiveMode();
        // 以二进制进行传输数据
        mFTPClient.setFileType(FTP.BINARY_FILE_TYPE);

        // 获取本地文件流
        File localFile = new File(localPath);
        if (!localFile.exists()) {
            System.err.println("本地文件不存在");
            return false;
        }
        //本地文件名
        String fileName = localFile.getName();

        // 如果远程文件包含 /
        if (remotePath.contains(File.separator)) {
            // 创建远程目录
            boolean isCreateOk = createDirectory(remotePath, mFTPClient);
            if (!isCreateOk) {
                System.err.println("远程文件夹创建失败");
                return false;
            }
        }
        // 列出远程目录上的文件
        FTPFile[] ftpFiles = mFTPClient.listFiles(remotePath);
        long remoteSize = 0L;

        // 定义上传后的文件名
        String remoteFilePath = remotePath + File.separator + fileName;
        // 如果目录下已经有文件
        if (ftpFiles.length > 0) {
            FTPFile mFtpFile = null;
            for (FTPFile ftpFile : ftpFiles) {
                if (ftpFile.getName().endsWith(fileName)) {
                    mFtpFile = ftpFile;
                    break;
                }
            }
            // 远程存在同名文件
            if (mFtpFile != null) {
                if (!mFTPClient.deleteFile(remoteFilePath)) {
                    System.err.println("服务端删除文件操作失败");
                }
            }
        }

        // 获取本地文件流
        FileInputStream fileInputStream = new FileInputStream(localFile);
        // 开始上传
        result = mFTPClient.storeFile(fileName, fileInputStream);
        if (!result) {
            return result;
        }
        return true;
    }


    /**
     * 下载文件保存在本地
     * @param remotePath 远程地址
     * @param localDir 保存在本地的地址
     * @return
     * @throws IOException
     */
    public boolean downLoad(String remotePath, String localDir) throws IOException {
        // 进入被动模式    每次数据连接之前,ftp client告诉ftp server开通一个端口来传输数据,ftp server可能每次开启不同的端口来传输数据,
        // 但是在Linux上,由于安全限制,可能某些端口没有开启,所以就出现阻塞。
        mFTPClient.enterLocalPassiveMode();
        // 以二进制进行传输数据
        mFTPClient.setFileType(FTP.BINARY_FILE_TYPE);
        // 获取要下载的ftp文件名列表
        FTPFile[] ftpFiles = mFTPClient.listFiles(remotePath);
        if (ftpFiles == null || ftpFiles.length == 0) {
            log.info("远程文件不存在");
            return false;
        } else if (ftpFiles.length > 1) {
            log.info("远程文件是文件夹");
            return false;
        }
        // 远程文件大小
        long lRemoteSize = ftpFiles[0].getSize();
        // 获取本地文件
        File localFileDir = new File(localDir);
        // 检查本地文件夹是否存在
        if (!localFileDir.exists()) {
            // 不存在就创建文件夹
            localFileDir.mkdirs();
        }
        // 用本地文件夹 和 ftp文件名 构建一个本地File对象
        File localFile = new File(localFileDir, ftpFiles[0].getName());
        long localSize = 0;
        FileOutputStream fos = null;
        // 如果文件已经存在
        if (localFile.exists()) {
            // 比较本地文件大小 和 远程FTP文件大小 如果大小一样就代表已经下载完毕
            if (localFile.length() == lRemoteSize) {
                System.err.println("已经下载完毕");
                return true;
            } else if (localFile.length() < lRemoteSize) {
                // 如果本地文件比远程FTP文件小 , 说明之前已经下载了
                localSize = localFile.length();
                // 要下载的文件存在,从本地文件大小的位置 进行断点续传  setRestartOffset: 断点续传方法
                mFTPClient.setRestartOffset(localSize);
                // 创建一个文件输出流以写入由指定的 File 对象表示的文件。如果第二个参数为真,则字节将写入文件的末尾而不是开头。创建一个新的 FileDescriptor 对象来表示此文件连接。
                fos = new FileOutputStream(localFile, true);
            }
        }
        if (fos == null) {
            fos = new FileOutputStream(localFile);
        }
        // 检索文件流
        InputStream is = mFTPClient.retrieveFileStream(remotePath);
        byte[] buffers = new byte[1024 * 5];
        long step = lRemoteSize / 10;
        long process = localSize / step;
        int len = -1;
        while ((len = is.read(buffers)) != -1) {
            // 二进制写入文件
            fos.write(buffers, 0, len);
            localSize += len;
            long newProcess = localSize / step;
            if (newProcess > process) {
                process = newProcess;
                System.err.println("下载进度:" + process);
            }
        }

        is.close();
        fos.close();
        boolean isDo = mFTPClient.completePendingCommand();
        return isDo;
    }




    /**
     * 连接ftp服务器
     * @return 是否连接成功
     * @throws SocketException
     * @throws IOException
     */
    private boolean openConnection()
            throws SocketException, IOException {
        // ftp ip地址
        String host = ftpConfig.getUrl();
        // ftp 端口号
        int port = ftpConfig.getPort();
        // ftp 账号
        String account = ftpConfig.getUsername();
        // ftp 密码
        String pwd = ftpConfig.getPassword();

        mFTPClient.setControlEncoding("UTF-8");

        // 连接FTP服务器,如果采用默认端口,可以使用ftp.connect(host)的方式直接连接FTP服务器
        mFTPClient.connect(host, port);

        // getReplyCode() 获取ftp应答 , FTPReply.isPositiveCompletion() 判断是否链接成功
        if (FTPReply.isPositiveCompletion(mFTPClient.getReplyCode())) {
            // 登录ftp服务器
            mFTPClient.login(account, pwd);
            // 判断是否链接成功
            if (FTPReply.isPositiveCompletion(mFTPClient.getReplyCode())) {
                // getSystemType() 从服务器获取系统类型并返回字符串   在第一次调用此方法后,该值在连接期间被缓存。换句话说,只有第一次调用此方法时,它才会向 FTP 服务器发出 SYST 命令。FTPClient 会记住该值并返回缓存的值,直到调用断开连接。
                FTPClientConfig config = new FTPClientConfig(mFTPClient.getSystemType().split(" ")[0]);
                config.setServerLanguageCode("zh");
                // 设置连接超时时间
                mFTPClient.setConnectTimeout(1000*30);
                mFTPClient.configure(config);
                return true;
            }
        }
        // 断开ftp连接
        disConnection();
        return false;
    }

    /**
     * 登出并断开连接
     */
    public void logout() {
        System.err.println("logout");
        if (mFTPClient.isConnected()) {
            System.err.println("logout");
            try {
                // 退出ftp
                mFTPClient.logout();
                disConnection();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 断开连接
     */
    private void disConnection() {
        if (mFTPClient.isConnected()) {
            try {
                mFTPClient.disconnect();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 创建远程目录,切换目录
     *
     * @param remote 远程目录
     * @param ftpClient ftp客户端
     * @return 是否创建成功
     * @throws IOException
     */
    public boolean createDirectory(String remote, FTPClient ftpClient) throws IOException {
        String dirctory = remote.substring(0, remote.lastIndexOf(File.separator) + 1);
        if (!dirctory.equalsIgnoreCase(File.separator) && !ftpClient.changeWorkingDirectory(remote)) {
            int start = 0;
            int end = 0;
            if (dirctory.startsWith(File.separator)) {
                start = 1;
            }
            end = dirctory.indexOf(File.separator, start);
            while (true) {
                String subDirctory = remote.substring(start, end);
                if (!ftpClient.changeWorkingDirectory(subDirctory)) {
                    if (ftpClient.makeDirectory(subDirctory)) {
                        ftpClient.changeWorkingDirectory(subDirctory);
                    } else {
                        System.err.println("创建目录失败");
                        return false;
                    }
                }
                start = end + 1;
                end = dirctory.indexOf(File.separator, start);
                if (end <= start) {
                    break;
                }
            }
        }
        ftpClient.changeWorkingDirectory(remote);
        return true;
    }
}

IFtpService

package com.vxdata.cases.modules.ftp.service;

public interface IFtpService {

    /**
     * 对外提供的上传文件方法
     * @param fileName  要上传的文件名
     * @param localPath 本地路径
     * @param remotePath    远程路径
     * @return
     */
    boolean ftpUpload(String fileName, String localPath, String remotePath);

    /**
     * 对外提供的下载文件方法
     * @param fileName  要下载的文件名
     * @param localPath 本地存储的路径
     * @param remotePath    远程路径
     * @return
     */
    boolean ftpDownload(String fileName, String localPath, String remotePath);

}

FtpServiceImpl

package com.vxdata.cases.modules.ftp.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.vxdata.cases.modules.file.exception.FastDFSException;
import com.vxdata.cases.modules.file.utils.FastDFSClient;
import com.vxdata.cases.modules.ftp.config.FtpConfig;
import com.vxdata.cases.modules.ftp.service.IFtpService;
import com.vxdata.cases.modules.ftp.utils.FtpUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.*;

@Service
@Slf4j
public class FtpServiceImpl implements IFtpService {
    @Autowired
    private FastDFSClient fastDFSClient;
    @Autowired
    FtpConfig ftpConfig;


    /**
     * 对外提供的上传文件方法
     * @param fileName  要上传的文件名
     * @param localPath 本地路径
     * @param remotePath    远程路径
     * @return
     */
    @Override
    public boolean ftpUpload(String fileName, String localPath, String remotePath) {
        return FtpUtil.ftpUpload(fileName,  localPath, remotePath);
    }


    /**
     * 对外提供的下载文件方法
     * @param fileName  要下载的文件名
     * @param localPath 本地存储的路径
     * @param remotePath    远程路径
     * @return
     */
    @Override
    public boolean ftpDownload(String fileName, String localPath, String remotePath) {
        return FtpUtil.ftpDownload(fileName,  localPath, remotePath);
    }


    /**
     * 将 InputStream 转成json对象
     * @param inputStream
     * @return
     * @throws IOException
     */
    public JSONObject inputStreamToString(InputStream inputStream) throws IOException{
        // 将FTP的文件流 转成String格式内容
        StringBuilder stringBuilder = new StringBuilder();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        boolean firstLine = true;
        String line = null; ;
        while((line = bufferedReader.readLine()) != null){
            if(!firstLine){
                stringBuilder.append(System.getProperty("line.separator"));
            }else{
                firstLine = false;
            }
            stringBuilder.append(line);
        }
        JSONObject jsonObject = JSON.parseObject(stringBuilder.toString());
        return jsonObject;
    }

    /**
     * String 转 InputStream
     * @param jsonStr
     * @return
     */
    public InputStream stringToInputStream(String jsonStr) {
        InputStream inputStream = new ByteArrayInputStream(jsonStr.getBytes());
        return inputStream;
    }


    /**
     * JSONObject 转 InputStream
     * @param jsonObject
     * @return
     */
    public InputStream objectToInputStream(JSONObject jsonObject) {
        String str = jsonObject.toString();
        InputStream inputStream = new ByteArrayInputStream(str.getBytes());
        return inputStream;
    }

    /**
     * 从fastDFS链接获取 InputStream
     */
    public InputStream getImgInputStream(String filepath) {
        InputStream inputStream = null;
        try {
            byte[] fileByte = fastDFSClient.download(filepath);
            inputStream = new ByteArrayInputStream(fileByte);
        } catch (FastDFSException e) {
            e.printStackTrace();
        }
        return inputStream;
    }

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值