Java 通过FTP与SFTP 方式, 实现 文件的上传下载 删除操作

1. FTP

FTP通讯协议采用客户机 / 服务器(Client / Server )架构。用户可以通过各种不同的FTP客户端程序,借助FTP协议,来连接FTP服务器,以上传或者下载文件。

默认端口: 21

  • 在此协议中SSH2服务器起了一个桥梁作用,把数据在客户端和ftp之间转发。ftp协议本身包括两个通道,一个是控制通道,另一个是数据通道。

在这里插入图片描述

2. SFTP

Sftp是Secure File Transfer Protocol的缩写,安全文件传送协议。可以为传输文件提供一种安全的加密方法。

  • sftp是ssh内含的协议,只要sshd服务器启动了,它就可用,它本身不需要ftp服务器启动
  • 它是作为SSH2的一个子服务工作的

在这里插入图片描述

3. SFTP 和FTPS的区别

1、安全通道

FTP 不提供任何安全通道来在主机之间传输文件;而SFTP协议提供了一个安全通道,用于在网络上的主机之间传输文件。

2、使用的协议

FTP使用TCP / IP协议。而,SFTP是SSH协议的一部分,它是一种远程登录信息。

3、链接方式

FTP使用TCP端口21上的控制连接建立连接。而,SFTP是在客户端和服务器之间通过SSH协议(TCP端口22)建立的安全连接来传输文件。

4、安全性

FTP密码和数据以纯文本格式发送,大多数情况下是不加密的,安全性不高。而,SFTP会在发送之前加密数据,二进制的形式传递,是无法“按原样”阅读的,安全性较高。

4. JAVA下针对于FTP实现上传下载工具类

import java.io.*;

import org.apache.commons.io.IOUtils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

/**
 * @Author: xiezb
 * @Date: 2019/9/23 10:14
 * @Description: ftp上传下载工具类
 */
@SuppressWarnings("ALL")
public class FtpUtil {
    /**文件编码*/
    private static String CODE = "UTF-8";
    /** ftp服务编码*/
    private static String SERVER_CODE = "ISO-8859-1";

    /**
     * 获取FTP连接 <br>
     * @param host FTP服务器hostname <br>
     * @param port FTP服务器端口 <br>
     * @param username FTP登录账号 <br>
     * @param password FTP登录密码 <br>
     * @return FTPClient对象 <br>
     */
    public static FTPClient getFTPConnect(String host, int port, String username, String password) {
        FTPClient ftp = new FTPClient();
        try {
            int reply;
            //1.连接服务器
            ftp.connect(host, port);
            //2.登录服务器 如果采用默认端口,可以使用ftp.connect(url)的方式直接连接FTP服务器
            ftp.login(username, password);
            //3.判断登陆是否成功
            reply = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftp.disconnect();
                return null;
            }
            //ftp.setFileType(FTPClient.BINARY_FILE_TYPE);//@fix 设置二进制解决偶有图图片传输失真问题
            return ftp;
        } catch (IOException e) {
            e.printStackTrace();
            closeFTP(ftp);
        }
        return null;
    }

    /**
     * 关闭FTP连接,释放资源 <br>
     * @param ftpClient 连接对象 <br>
     */
    public static void closeFTP(FTPClient ftpClient) {
        if (!ObjectUtil.isEmptyObject(ftpClient) && ftpClient.isConnected()) {
            try {
                ftpClient.logout();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    ftpClient.disconnect();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * Description: 向FTP服务器上传文件 <br>
     * @param ftp 连接对象 <br>
     * @param basePath FTP服务器基础目录 <br>
     * @param filePath FTP服务器文件存放路径。文件的路径为basePath+filePath <br>
     * @param filename 上传到FTP服务器上的文件名 <br>
     * @param input 输入流 <br>
     * @return 成功返回true,否则返回false <br>
     */
    public static boolean uploadFile(FTPClient ftp, String basePath,
                                     String filePath, String filename, InputStream input) {
        try {
            if (ObjectUtil.isEmptyObject(ftp)) {
                return false;
            }
            if (!ObjectUtil.isEmptyObject(basePath)) {
                 basePath = basePath.replace("\\", "/"); // 配置中可能配置的是windows的,换Linux "/"
                 basePath = basePath.endsWith("/") ? basePath.substring(0, basePath.length() - 1) : basePath;
            }
            String tempPath = basePath;
            if (!ObjectUtil.isEmptyObject(filePath)) {
                filePath = filePath.replace("\\", "/"); // 配置中可能配置的是windows的,换Linux "/"
                if (filePath.startsWith("/")) {
                    tempPath += filePath;
                } else {
                    if (ObjectUtil.isEmptyObject(tempPath)) {
                        tempPath = filePath;
                    } else {
                        tempPath = tempPath + "/" + filePath;
                    }
                }
            }
            //切换到上传目录
            if (!ftp.changeWorkingDirectory(tempPath)) {
                //如果目录不存在创建目录
                String[] dirs = tempPath.split("/");
                String path = "";
                for (String dir : dirs) {
                    if (ObjectUtil.isEmptyObject(dir)) continue;
                    if (tempPath.startsWith("/")) {
                        path += "/" + dir;
                    } else  {
                        if (ObjectUtil.isEmptyObject(path)) {
                            path += dir;
                        } else {
                            path += "/" + dir;
                        }
                    }
                    if (!ftp.changeWorkingDirectory(path)) {  //进不去目录,说明该目录不存在
                        if (!ftp.makeDirectory(path)) { //创建目录
                            //如果创建文件目录失败,则返回
                            System.out.println("创建文件目录"+path+"失败");
                            return false;
                        } else {
                            //目录存在,则直接进入该目录
                            ftp.changeWorkingDirectory(path);
                        }
                    }
                }
            }
            //设置上传文件的类型为二进制类型
            ftp.setFileType(FTP.BINARY_FILE_TYPE);
            //上传文件
            filename = new String(filename.getBytes(CODE), SERVER_CODE);
            if (!ftp.storeFile(filename, input)) {
                return false;
            }
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            closeFTP(ftp);
        }
        return false;
    }

    /**
     * Description: 从FTP服务器下载文件 <br>
     * @param ftp 连接对象 <br>
     * @param remotePath FTP服务器上的相对路径 <br>
     * @param fileName 要下载的文件名 <br>
     * @param localPath 下载后保存到本地的路径 <br>
     * @return  结果: <br>
     *          true: 成功; false: 失败 <br>
     */
    public static boolean downloadFile(FTPClient ftp, String remotePath,
                                       String fileName, String localPath) {
        try {
            if (ObjectUtil.isEmptyObject(ftp)) {
                return false;
            }
            ftp.setControlEncoding(CODE);
            ftp.changeWorkingDirectory(remotePath);// 转移到FTP服务器目录
            FTPFile[] fs = ftp.listFiles();
            for (FTPFile ff : fs) {
                if (ff.getName().equals(fileName)) {
                    localPath = localPath.replace("\\", File.separator);
                    localPath = localPath + (localPath.endsWith(File.separator) ? fileName : "/" + fileName);
                    File file = file = new File(localPath);
                    if (file.exists()) {
                        file.delete();
                    }
                    file.createNewFile();
                    file = new File(localPath);
                    OutputStream is = new FileOutputStream(file);
                    ftp.retrieveFile(ff.getName(), is);
                    is.close();
                }
            }
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            closeFTP(ftp);
        }
        return false;
    }

    /**
     * Description: 从FTP服务器下载文件 <br>
     * @param ftp 连接对象 <br>
     * @param remotePath FTP服务器上的相对路径 <br>
     * @param fileName 要下载的文件名 <br>
     * @return  结果: 文件的二进制数组 <br>
     *
     */
    public static byte[] downloadFile(FTPClient ftp, String remotePath, String fileName) {
        byte[] bytes = null;
        try {
            if (ObjectUtil.isEmptyObject(ftp)) {
                return null;
            }
            ftp.setControlEncoding(CODE);
            ftp.setFileType(ftp.BINARY_FILE_TYPE);
            ftp.setBufferSize(1024);
            ftp.changeWorkingDirectory(remotePath);// 转移到FTP服务器目录
            FTPFile[] fs = ftp.listFiles();
            for (FTPFile ff : fs) {
                if (ff.getName().equals(fileName)) {
                    String remoteAbsoluteFile = ff.getName();
                    remoteAbsoluteFile = new String(remoteAbsoluteFile.getBytes(CODE), SERVER_CODE);
                    InputStream in  = ftp.retrieveFileStream(remoteAbsoluteFile);

                    bytes = IOUtils.toByteArray(in);
                    System.out.println("下载成功!" + bytes.length);
                    in.close();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            closeFTP(ftp);
        }
        return bytes;
    }

    /**
     * 文件转成 byte[]
     * @param inStream
     * @return
     * @throws IOException
     */
    public static byte[] input2byte(InputStream inStream) throws IOException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
        byte[] b = new byte[1024];
        int len = -1;
        while((len = inStream.read(b)) != -1) {
            bos.write(b, 0, len);
        }
        bos.flush();
        byte[] in2b = bos.toByteArray();
        bos.close();
        return in2b;
    }
    /**
     * 删除文件-FTP方式 <br>
     *
     * @param ftp         FTPClient对象 <br>
     * @param ftpPath     FTP服务器上传地址 <br>
     * @param ftpFileName FTP服务器上要删除的文件名 <br>
     * @return
     */
    public static void deleteFile(FTPClient ftp, String ftpPath, String ftpFileName) throws Exception{
        try {
            ftp.changeWorkingDirectory(ftpPath);//转移到指定FTP服务器目录
            ftpFileName = new String(ftpFileName.getBytes(CODE), SERVER_CODE);
            ftp.deleteFile(ftpFileName);
        } catch (Exception e){
            e.printStackTrace();
            throw e;
        } finally {
            closeFTP(ftp);
        }
    }


    //ftp上传文件测试main函数
    public static void main(String[] args) {
        try {
           FileInputStream in=new FileInputStream(new File("F:\\abc\\201909\\哈哈.txt"));
           FTPClient ftp = getFTPConnect("ip",21,"用户名","密码");
            // 上传 
            boolean flag = uploadFile(ftp, "","上传路径目录", "哈哈.txt", in);
        
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

5. Java操作SFTP 工具类

import com.jcraft.jsch.*;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.Properties;
import java.util.Vector;
/**
 * @Author: xiezb
 * @Date: 2019/9/23 13:13
 * @Description: 类说明 sftp工具类
 */
@SuppressWarnings("ALL")
public class SFTPUtil {
    private transient Logger log = LoggerFactory.getLogger(this.getClass());

    private ChannelSftp sftp;
    private Session session;
    /** SFTP 登录用户名*/
    private String username;
    /** SFTP 登录密码*/
    private String password;
    /** 私钥 */
    private String privateKey;
    /** SFTP 服务器地址IP地址*/
    private String host;
    /** SFTP 端口*/
    private int port;
    /**默认连接超时*/
    private static Integer timeOut = 20000;

    /**文件编码*/
    private static String FILE_CODE = "UTF-8";

    /**
     *  构造基于密码认证的sftp对象 <br>
     * @param host 主机 <br>
     * @param port 端口号 <br>
     * @param username 用户名 <br>
     * @param password 密码 <br>
     */
    public SFTPUtil(String host, int port, String username, String password) {
        this.username = username;
        this.password = password;
        this.host = host;
        this.port = port;
    }

    /**
     * 构造基于秘钥认证的sftp对象 <br>
     * @param username 用户名 <br>
     * @param host 主机 <br>
     * @param port 端口 <br>
     * @param privateKey 私钥 <br>
     */
    public SFTPUtil(String username, String host, int port, String privateKey) {
        this.username = username;
        this.host = host;
        this.port = port;
        this.privateKey = privateKey;
    }

    public SFTPUtil(){}


    /**
     * 连接sftp服务器
     */
    public void login(){
        try {
            JSch jsch = new JSch();
            if (privateKey != null) {
                jsch.addIdentity(privateKey);// 设置私钥
            }

            session = jsch.getSession(username, host, port);

            if (password != null) {
                session.setPassword(password);
            }
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");

            session.setConfig(config);
            session.setTimeout(timeOut);

            session.connect();

            Channel channel = session.openChannel("sftp");
            channel.connect();

            sftp = (ChannelSftp) channel;
            sftp.setFilenameEncoding(FILE_CODE);
        } catch (Exception e) {
            e.printStackTrace();
            this.logout();
        }
    }

    /**
     * 关闭连接 server
     */
    public void logout(){
        if (!ObjectUtil.isEmptyObject(sftp)) {
            if (sftp.isConnected()) {
                sftp.disconnect();
            }
        }
        if (!ObjectUtil.isEmptyObject(session)) {
            if (session.isConnected()) {
                session.disconnect();
            }
        }
    }

    /**
     * 将输入流的数据上传到sftp作为文件。文件完整路径=basePath+directory  <br>
     * @param basePath  服务器的基础路径  <br>
     * @param directory  上传到该目录  <br>
     * @param sftpFileName  sftp端文件名 <br>
     * @param input   输入流 <br>
     */
    public boolean uploadFile(String basePath,String directory, String sftpFileName, InputStream input) throws SftpException{
        String tempPath = "";
        try {
            if (!ObjectUtil.isEmptyObject(basePath)) {
                basePath = basePath.replace("\\", "/"); // 配置中可能配置的是windows的,换Linux "/"
                basePath = basePath.endsWith("/") ? basePath.substring(0, basePath.length() - 1) : basePath;
            }
            tempPath = basePath;
            if (!ObjectUtil.isEmptyObject(directory)) {
                directory = directory.replace("\\", "/"); // 配置中可能配置的是windows的,换Linux "/"
                if (directory.startsWith("/")) {
                    tempPath += directory;
                } else {
                    if (ObjectUtil.isEmptyObject(tempPath)) {
                        tempPath = directory;
                    } else {
                        tempPath = tempPath + "/" + directory;
                    }
                }
            }
            sftp.cd(tempPath);
        } catch (SftpException e) {
            //目录不存在,则创建文件夹
            String [] dirs= tempPath.split("/");
            String path = "";
            for(String dir : dirs){
                if(ObjectUtil.isEmptyObject(dir)) continue;
                if (tempPath.startsWith("/")) {
                    path += "/" + dir;
                } else  {
                    if (ObjectUtil.isEmptyObject(path)) {
                        path += dir;
                    } else {
                        path += "/" + dir;
                    }
                }
                try{
                    sftp.cd(path);
                }catch(SftpException ex){
                    sftp.mkdir(path);
                    sftp.cd(path);
                }
            }
        }
        sftp.put(input, sftpFileName);  //上传文件
        this.logout();
        return true;
    }


    /**
     * 下载文件 到 指定目录   <br>
     * @param directory 下载目录  <br>
     * @param downloadFile 下载的文件   <br>
     * @param saveFile 存在本地的路径  <br>
     */
    public boolean downloadFile(String directory, String downloadFile, String saveFile) throws SftpException, IOException {
        try {
            if (!ObjectUtil.isEmptyObject(directory)) {
                sftp.cd(directory);
            }
            saveFile = saveFile.replace("\\", File.separator);
            saveFile = saveFile + (saveFile.endsWith(File.separator) ? downloadFile : "/" + downloadFile);
            File file = file = new File(saveFile);
            if (file.exists()) {
                file.delete();
            }
            file.createNewFile();
            file = new File(saveFile);
            sftp.get(downloadFile, new FileOutputStream(file));
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        } finally {
            this.logout();
        }
    }

    /**
     * 下载文件,获取二进制数组  <br>
     * @param directory 下载目录 <br>
     * @param downloadFile 下载的文件名 <br>
     * @return 字节数组 <br>
     */
    public byte[] downloadFile(String directory, String downloadFile) throws SftpException, IOException{
        try {
            if (!ObjectUtil.isEmptyObject(directory)) {
                sftp.cd(directory);
            }
            InputStream is = sftp.get(downloadFile);
            byte[] fileData = IOUtils.toByteArray(is);
            return fileData;
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        } finally {
            this.logout();
        }
    }


    /**
     * 删除文件  <br>
     * @param directory 要删除文件所在目录 <br>
     * @param deleteFile 要删除的文件 <br>
     */
    public void deleteFile(String directory, String deleteFile) throws SftpException{
        try {
            sftp.cd(directory);
            sftp.rm(deleteFile);
        } catch (SftpException e) {
            e.printStackTrace();
            throw e;
        } finally {
            this.logout();
        }
    }


    /**
     * 列出目录下的文件 <br>
     * @param directory 要列出的目录 <br>
     */
    public Vector<?> listFiles(String directory) throws SftpException {
        try {
           return  sftp.ls(directory);
        } catch (SftpException e) {
            e.printStackTrace();
            throw e;
        } finally {
            this.logout();
        }
    }

    //上传文件测试
    public static void main(String[] args) throws SftpException, IOException {
        SFTPUtil sftp = new SFTPUtil("ip",22,"用户名","密码");
        sftp.login();
        FileInputStream is =new FileInputStream(new File("F:\\abc\\哈哈.txt"));
       // sftp.uploadFile("","文件上传目录", "哈哈.txt", is);
       // sftp.downloadFile("文件所在目录", "哈哈.txt","F:/abc");
     
       
        sftp.logout();
    }

6. 判断空工具

import java.util.*;
/**
 * 字符串工具类
 */
public class ObjectUtil {
	/**
	 * 判断对象是否为空
	 * @Author: xiezb
	 * @param obj 对象
	 * @return 是否为空
	 */
	public static boolean isEmptyObject(Object obj) {
		return obj == null;
	}

	/**
	 * 判断哈希是否为空
	 * @Author: xiezb
	 * @param map 哈希
	 * @return 是否为空
	 */
	public static boolean isEmptyObject(Map<?, ?> map) {
		return (map == null || map.size() == 0);
	}

	/**
	 * 判断字符是否为空
	 * @Author: xiezb
	 * @param str 字符
	 * @return 是否为空
	 */
	public static boolean isEmptyObject(String str) {
		return (str == null || "".equals(str) || "null".equalsIgnoreCase(str) || str.trim().length() == 0);
	}

	/**
	 * 判断数组是否为空
	 * @Author: xiezb
	 * @param arr 数组
	 * @return 是否为空
	 */
	public static boolean isEmptyObject(Arrays[] arr) {
		return (arr == null || arr.length == 0);
	}

	/**
	 * 判断列表是否为空
	 * @Author: xiezb
	 * @param lis 列表
	 * @return 是否为空
	 */
	public static boolean isEmptyObject(List<?> lis) {
		return (lis == null || lis.size() == 0);
	}

	/**
	 * 判断集合是否为空
	 * @Author: xiezb
	 * @param ita 集合
	 * @return 是否为空
	 */
	public static boolean isEmptyObject(Iterator<?> ita) {
		return (ita == null || !ita.hasNext());
	}

	/**
	 * 判断缓存是否为空
	 * @Author: xiezb
	 * @param sbf 缓存
	 * @return 是否为空
	 */
	public static boolean isEmptyObject(StringBuffer sbf) {
		return (sbf == null || sbf.length() == 0);
	}

}
  • 到此, 可通过上面代码自行测试, 快动手试试吧
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值