JAVA FTP/SFTP 上传下载文件

1.FTP 工具类

package com.example.demo.utlis;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;

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

public class FtpUtil2 {

    private static FTPClient ftpClient = new FTPClient();

    /**
     * 获取FTPClient对象
     *
     * @param ftpHost     FTP主机服务器
     * @param ftpPassword FTP 登录密码
     * @param ftpUserName FTP登录用户名
     * @param ftpPort     FTP端口 默认为21
     * @return
     */
    public FTPClient getFTPClient(String ftpHost, String ftpUserName,
                                  String ftpPassword, int ftpPort) {

        try {

            ftpClient.connect(ftpHost, ftpPort);// 连接FTP服务器
            ftpClient.login(ftpUserName, ftpPassword);// 登陆FTP服务器
            if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
                System.out.println("未连接到FTP,用户名或密码错误。");
                ftpClient.disconnect();
            } else {
                System.out.println("FTP连接成功。");
            }
        } catch (SocketException e) {
            e.printStackTrace();
            System.out.println("FTP的IP地址可能错误,请正确配置。");
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("FTP的端口错误,请正确配置。");
        }
        return ftpClient;
    }


    /**
     * 从FTP服务器下载文件
     *
     * @param ftpPath   FTP服务器中文件所在路径
     * @param localPath 下载到本地的位置
     * @param fileName  文件名称
     */
    public void downloadFtpFile(String ftpPath, String localPath,
                                String fileName) {
        try {

            ftpClient.setControlEncoding("UTF-8"); // 中文支持
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
            ftpClient.enterLocalPassiveMode();
            ftpClient.changeWorkingDirectory(ftpPath);

            File localFile = new File(localPath + File.separatorChar + fileName);
            OutputStream os = new FileOutputStream(localFile);
            ftpClient.retrieveFile(fileName, os);
            os.close();
            ftpClient.logout();

        } catch (FileNotFoundException e) {
            System.out.println("没有找到" + ftpPath + "文件");
            e.printStackTrace();
        } catch (SocketException e) {
            System.out.println("连接FTP失败.");
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("文件读取错误。");
            e.printStackTrace();
        }

    }

    /**
     * Description: 向FTP服务器上传文件
     *
     * @param ftpPath  FTP服务器中文件所在路径 格式: ftptest/aa
     * @param fileName ftp文件名称
     * @param input    文件流
     * @return 成功返回true,否则返回false
     */
    public boolean uploadFile(String ftpPath,
                              String fileName, InputStream input) {
        boolean success = false;

        try {
            int reply;

            reply = ftpClient.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftpClient.disconnect();
                return success;
            }
            ftpClient.setControlEncoding("UTF-8"); // 中文支持
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
            ftpClient.enterLocalPassiveMode();
            ftpClient.changeWorkingDirectory(ftpPath);

            ftpClient.storeFile(fileName, input);

            input.close();
            ftpClient.logout();
            success = true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ftpClient.isConnected()) {
                try {
                    ftpClient.disconnect();
                } catch (IOException ioe) {
                }
            }
        }
        return success;
    }


    public static void main(String args[]) {

        String ftpHost = "ftp://localhost";
        String ftpUserName = "admin";
        String ftpPassword = "admin";
        Integer port = 21;
        String ftpPath = "/";
        String localPath = "F:\\";
        String fileName = "111.jpg";
        //上传一个文件
        try {

//            FileInputStream in = new FileInputStream(new File(localPath));
            FtpUtil2 ftpUtil = new FtpUtil2();

            ftpUtil.getFTPClient(ftpHost, ftpUserName, ftpPassword, port);
            // 上传文件
//            boolean flag = ftpUtil.uploadFile(ftpPath, fileName, in);
            // 下载文件
            ftpUtil.downloadFtpFile("/1.jpg", localPath, fileName);
//            if (flag) {
//                System.out.println("文件上传ftp成功,请检查ftp服务器。");
//
//            } else {
//                System.out.println("文件上传ftp异常。请重试!");
//
//            }
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(e);
        }
    }

}

 



2.SFTP 工具类

package com.example.demo.utlis;

import com.jcraft.jsch.*;

import java.io.*;
import java.util.Properties;

public class SFtpUtils {

    // 初始化单例对象
    private static SFtpUtils sFtpUtils = new SFtpUtils();
    private  String host;//服务器连接ip
    private String username;//用户名
    private String password;//密码
    private int port = 22;//端口号
    private ChannelSftp sftp = null;
    private Session sshSession = null;

    /**
     * 初始化sftp的单例对象
     * @return
     */
    public static SFtpUtils getInstance()
    {
        return sFtpUtils;
    }


    /**
     *  初始化sft链接信息,必须先做这个
     * @param host 远程主机ip
     * @param port 端口号
     * @param username 账号
     * @param password 密码
     */
    public  void init(String host, int port, String username, String password)
    {
        this.host = host;
        this.username = username;
        this.password = password;
        this.port = port;

    }




    /**
     * 通过SFTP连接服务器
     */
    public void connect()
    {
        try
        {
            JSch jsch = new JSch();
            jsch.getSession(username, host, port);
            sshSession = jsch.getSession(username, host, port);
            sshSession.setPassword(password);
            Properties sshConfig = new Properties();
            sshConfig.put("StrictHostKeyChecking", "no");
            sshSession.setConfig(sshConfig);
            sshSession.connect();
            Channel channel = sshSession.openChannel("sftp");
            channel.connect();
            sftp = (ChannelSftp) channel;

        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    /**
     * 关闭连接
     */
    public void disconnect()
    {
        if (this.sftp != null)
        {
            if (this.sftp.isConnected())
            {
                this.sftp.disconnect();

            }
        }
        if (this.sshSession != null)
        {
            if (this.sshSession.isConnected())
            {
                this.sshSession.disconnect();

            }
        }
    }

    /**
     *  sftp下载文件
     * @param remoteFielPath  远程文件路径
     * @param localFilePath 本地下载路径
     * @return
     * @throws SftpException
     * @throws FileNotFoundException
     */
    public boolean downLoadFile(String remoteFielPath,String localFilePath) throws SftpException, FileNotFoundException {
        // 检查文件是否存在
        SftpATTRS sftpATTRS = sftp.lstat(remoteFielPath);
        if(!sftpATTRS.isReg()){
            // 不是一个文件,返回false
            return false;
        }
        // 下载文件到本地
        sftp.get(remoteFielPath,localFilePath);

        return true;
    }

    /**
     * 下载文件放回文件数据
     * @param remoteFielPath
     * @return
     * @throws SftpException
     * @throws IOException
     */
    public boolean downLoadFileTwo(String remoteFielPath, String localFilePath) throws SftpException, IOException {
        // 检查文件是否存在
        SftpATTRS sftpATTRS = sftp.lstat(remoteFielPath);
        // 判断是否是一个文件
        if(sftpATTRS.isReg()){
            // 下载文件到本地
            InputStream inputStream = sftp.get(remoteFielPath);
            /**今天想写下从sftp下载文件到本地,虽然sftp提供了get(String remotePath,String LocalPath)方法,将远程文件写入到本地。
             * 但还是想属性下从远程获取InputStream对象写入到本地的方式。
             * 遇到的问题:刚开始只想这实现,就是获取byte对象写入到本地文件,先用ByteArrayInputStream怎么转都无法获取到bytes对象
             * 放入到FileOutputStream对象中。搞了老半天都没有搞定,或许有ByteArrayInputStream对象下载的方式但没有找到。
             * 正解:如下*/
            // 通过BufferedInputStream对象缓存输入流对象获取远程的输入流
            BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
            // 创建本地文件信息
            File file = new File(localFilePath);
            // 将本地文件放入到 本地文件输出流
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            // 将本地文件输出流 放入到 缓存输出流对象
            BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
            // 声明每次获取的byte长度
            int len = 2048;
            // 初始化byte[]
            byte[] bytes = new byte[len];
            /**通过BufferedInputStream对象获取 远程文件 InputStream的bytes字节信息,并循环添加到BufferedOutputStream缓存输出流对象中,
             * 将远程bytes数据写入到本地文件中
             * 遇到的问题:这里我一直纠结于为什么这样写会实现想要的效果,是如何写入到本地的
             * 其实这不是开发中遇到的问题的事情了,是自己困于自己设定的一个纠结情绪中了。也就是俗称的牛角尖。
             * 切记,一定不可以钻牛角尖。因为开发都是有语言规则的。按照规则来就能实现效果,脱离规则即使神仙也无能为力。
             * */
            while ((len = bufferedInputStream.read(bytes)) != -1){
                bufferedOutputStream.write(bytes,0,len);
            }
            bufferedOutputStream.flush();
            bufferedInputStream.close();
            bufferedOutputStream.close();
            fileOutputStream.close();
            inputStream.close();
            return true;
        }
        return false;

    }
    /**
     * 上传单个文件,通过文件路径上传
     * @param remotePath:远程保存目录
     * @param remoteFileName:保存文件名
     * @param localPath:本地上传目录(以路径符号结束)
     * @param localFileName:上传的文件名
     * @return
     */
    public boolean uploadFile(String remotePath, String remoteFileName,String localPath, String localFileName)
    {
        FileInputStream in = null;
        try
        {   // 创建目录
            createDir(remotePath);
            File file = new File(localPath + localFileName);
            in = new FileInputStream(file);
            sftp.put(in, remoteFileName);
            return true;
        }catch (FileNotFoundException e)
        {
            e.printStackTrace();
        }catch (SftpException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (in != null)
            {
                try
                {
                    in.close();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }

    /**
     * 上传文件到sftp,通过输入流上传
     * @param remotePath
     * @param remoteFileName
     * @param inputStream
     * @return
     */
    public boolean uploadFile(String remotePath, String remoteFileName,InputStream inputStream)
    {
        FileInputStream in = null;
        try
        {   // 创建目录
            createDir(remotePath);
            sftp.put(inputStream, remoteFileName);
            return true;
        }catch (SftpException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (in != null)
            {
                try
                {
                    in.close();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }

    /**
     * 创建目录
     * @param createpath
     * @return
     */
    public boolean createDir(String createpath)
    {
        try
        {
            if (isDirExist(createpath))
            {
                // 有时候,开发在填写路径的时候第一个位置会忘记加"/"的根路径
                // 这回引发cd操作是发生:NO Such File 异常,所以这里处理下
                if(!(createpath.substring(0,1)=="/")){
                    createpath="/"+createpath;
                }
                this.sftp.cd(createpath);
                return true;
            }
            String pathArry[] = createpath.split("/");
            StringBuffer filePath = new StringBuffer("/");
            for (String path : pathArry)
            {
                if (path.equals(""))
                {
                    continue;
                }
                filePath.append(path + "/");
                if (isDirExist(filePath.toString()))
                {
                    sftp.cd(filePath.toString());
                }
                else
                {
                    // 建立目录
                    sftp.mkdir(filePath.toString());
                    // 进入并设置为当前目录
                    sftp.cd(filePath.toString());
                }

            }
            this.sftp.cd(createpath);
            return true;
        }
        catch (SftpException e)
        {
            e.printStackTrace();
        }
        return false;
    }



    /**
     * 判断目录是否存在,linux目录必须最前方带有"/"
     * @param directory
     * @return
     */
    public boolean isDirExist(String directory)
    {
        boolean isDirExistFlag = false;
        try
        {
            // 有时候,开发在填写路径的时候第一个位置会忘记加"/"的根路径
            // 这回引发cd操作是发生:NO Such File 异常,所以这里处理下
            if(!(directory.substring(0,1)=="/")){
                directory="/"+directory;
            }
            SftpATTRS sftpATTRS = sftp.lstat(directory);
            isDirExistFlag = true;
            return sftpATTRS.isDir();
        }
        catch (Exception e)
        {
            if (e.getMessage().toLowerCase().equals("no such file"))
            {
                isDirExistFlag = false;
            }
        }
        return isDirExistFlag;
    }


    public static void main(String arg[]) throws IOException, SftpException {
        // 获取图片的InputStream对象,并将图片生成到sftp上
        SFtpUtils sFtpUtils= SFtpUtils.getInstance();
        sFtpUtils.init("localhost",22, "admin", "admin");
        sFtpUtils.connect();
        // 上传文件
        /*File file = new File("F:\\OK.jpg");
        InputStream in = new FileInputStream(file);
        boolean flag = sFtpUtils.uploadFile("/app/xwapp/Test","1111.jpg",in);*/

        // 下载文件到本地方法1
        // boolean flag = sFtpUtils.downLoadFile("/app/xwapp/Test/1111.jpg","F:\\OKbak.jpg");
        // 下载文件到本地方法2
        boolean flag = sFtpUtils.downLoadFileTwo("/1.jpg","F:\\OKbak.jpg");
        if(flag){
            System.out.println("处理成功");
        }else {
            System.out.println("处理失败");
        }
        sFtpUtils.disconnect();
    }
}

 




////////////////////////////////////
配置虚拟路径 application.properties

 

# 虚拟路径配置(win系统自行变更本地路径)

web.upload.path=F:/Test/

spring.mvc.static-path-pattern=/**

spring.resources.static-locations=file:${web.upload.path},classpath:/apk/,classpath:/static/

 

 


posted @ 2021-05-28 17:10  Forever丶随风  阅读(882)  评论(0编辑  收藏  举报