java连接ftp和sftp的区别(最详细)

用ftp连接方式会报SSH访问失败,改成sftp连接。这个SSH到底是啥呢?先做个解释说明:

是一种加密的网络传输协议,可在不安全的网络中为网络服务提供安全的传输环境。SSH通过在网络中创建安全隧道来实现SSH客户端与服务器之间的连接

@Slf4j
public class FtpUtil {
        @Value("${ftp.host}")
        private String host;
        @Value("${ftp.username}")
        private String username;
        @Value("${ftp.password}")
        private String password;

        private static String ftpFilePath = "/learning/weidai/data/document.js";

        public static void main(String[] args) {
            FtpUtil ftpUtil = new FtpUtil();
            //下载文件
            //ftpUtil.downLoadFile(ftpFilePath);
        }

        /**
         * 建立连接,登录
         * @return
         */
        public  FTPClient connectAndLogin(){
            FTPClient ftpClient = new FTPClient();
            try {
                //连接服务器
                ftpClient.connect(host,21);
                //登录
                boolean flag = ftpClient.login(username,password);
                if(flag){
                    log.info("建立连接,登录ftp成功");
                    return ftpClient;
                }else{
                    log.error("登录ftp失败");
                    return null;
                }

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

        /**
         * 退出登录,断开连接
         * @param ftpClient
         */
        public  void logoutAndDisconnect(FTPClient ftpClient){
            if(ftpClient!=null && ftpClient.isConnected()){
                try {
                    //退出登录
                    ftpClient.logout();
                    //断开连接
                    ftpClient.disconnect();
                    System.out.println("退出登录,断开连接");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        /***
         * 上传文件
         */
        public void uploadFile(){
            FtpUtil ftpUtil = new FtpUtil();
            FTPClient ftpClient = ftpUtil.connectAndLogin();
            if(ftpClient == null){
                return;
            }
            //本地文件
            File file = new File("file.pdf");

            //将目录名称转为iso-8859-1编码 (FTP协议里面,规定文件名编码为iso-8859-1)
            String validPath = new String(ftpFilePath.getBytes(), StandardCharsets.ISO_8859_1);

            //文件上传到ftp的文件名
            String fileName = "测试.txt";
            // FTP协议里面,规定文件名编码为iso-8859-1
            String ftpFileName = new String(fileName.getBytes(),StandardCharsets.ISO_8859_1);

            //文件输入流 FileIntPutStream
            FileInputStream fis = null;
            try {
                fis = new FileInputStream(file);
                //设置缓冲区大小 4M
                ftpClient.setBufferSize(4*1024*1024);
                //设置编码
                ftpClient.setControlEncoding("utf-8");

                boolean changeWorkDirFlag = ftpClient.changeWorkingDirectory(validPath);
                if(!changeWorkDirFlag){
                    //创建子目录
                    createDirectory(ftpClient,validPath);
                }
                //存储文件至ftp服务器
                boolean flag = ftpClient.storeFile(ftpFileName,fis);
                System.out.println("上传文件"+(flag?"成功":"失败"));
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                ftpUtil.logoutAndDisconnect(ftpClient);
            }

        }


        /**
         *
         * 在根目录下创建目录,我自己搭建的vsftp服务器根目录是/root,因此是在/root下创建目录
         * @param ftpClient ftp客户端
         * @param directory 文件目录,将在根目录下创建
         */
        public  void createDirectory(FTPClient ftpClient,String directory) {

            String fileSeparator = "/";
            if (!directory.endsWith(fileSeparator)) {
                directory += fileSeparator;
            }
            int fromIndex = 0;
            int endIndex = 0;
            try {
                if(ftpClient.changeWorkingDirectory(directory)){
                    //如果目录存在,直接返回
                    return;
                }
                if (directory.startsWith(fileSeparator)) {
                    fromIndex = 1;
                }
                endIndex = directory.indexOf(fileSeparator, fromIndex);
                while (true) {
                    String subDirectory = new String(directory.substring(fromIndex, endIndex));
                    if (!ftpClient.changeWorkingDirectory(subDirectory)) {
                        if (ftpClient.makeDirectory(subDirectory)) {
                            ftpClient.changeWorkingDirectory(subDirectory);
                        } else {
                            System.out.println("创建"+subDirectory+"目录失败");
                            return;
                        }
                    }
                    fromIndex = endIndex + 1;
                    endIndex = directory.indexOf(fileSeparator, fromIndex);
                    //检查所有目录是否创建完毕
                    if (endIndex <= fromIndex) {
                        break;
                    }
                }
                System.out.println("上传目录创建成功");
            } catch (Exception e) {
                System.out.println("上传目录创建失败");
                e.printStackTrace();
            }
        }

        /**
         * 下载文件
         */
        public static byte[] downLoadFile(String filePath){
            FtpUtil ftpUtil = new FtpUtil();
            FTPClient ftpClient = ftpUtil.connectAndLogin();
            if(ftpClient == null){
                return null;
            }
            //ftp服务器文件名
            String validFtpFilePath = new String(filePath.getBytes(),StandardCharsets.ISO_8859_1);
            //下载到本地地址
            String localPath = "file.pdf";
            try {
                OutputStream os = new FileOutputStream(localPath);
                //1、检查文件是否存在
                if(!isFileExist(filePath,ftpClient)){
                    log.info("文件不存在");
                    return null;
                }
                boolean flag = ftpClient.retrieveFile(validFtpFilePath,os);
                log.info("下载文件"+(flag?"成功":"失败"));
                //转换为byte流
                FileInputStream fis = new FileInputStream(localPath);
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                byte[] b = new byte[1024];
                int n;
                while ((n = fis.read(b)) != -1)
                {
                    bos.write(b, 0, n);
                }
                fis.close();
                bos.close();
                byte[] buffer  = bos.toByteArray();
                return buffer;
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                ftpUtil.logoutAndDisconnect(ftpClient);
            }
            return null;
        }


        /**
         * 判断文件是否存在
         * @param ftpFile
         * @param ftpClient
         * @return
         */
        public static Boolean isFileExist(String ftpFile, FTPClient ftpClient) {
            if (ftpClient != null) {
                try {
                    String validFtpFile = new String(ftpFile.getBytes(),StandardCharsets.ISO_8859_1);
                    String path = validFtpFile.substring(0,validFtpFile.lastIndexOf("/"));
                    String fileName = validFtpFile.substring(validFtpFile.lastIndexOf("/")+1);
                    // 判断是否存在该目录
                    boolean changeWorkDirFlag = ftpClient.changeWorkingDirectory(path);
                    if (!changeWorkDirFlag) {
                        System.out.println("目录不存在");
                        return false;
                    }
                    ftpClient.enterLocalPassiveMode();  // 设置被动模式,开通一个端口来传输数据
                    String[] fs = ftpClient.listNames();
                    // 判断该目录下是否有文件
                    if (fs == null || fs.length == 0) {
                        System.out.println("该目录下没有文件");
                        return false;
                    }
                    for (String ftpName : fs) {
                        if (ftpName.equals(fileName)) {
                            return true;
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return false;
        }


        /**
         * 删除文件
         */
        public void deleteFile(){
            FtpUtil ftpUtil = new FtpUtil();
            FTPClient ftpClient = ftpUtil.connectAndLogin();
            if(ftpClient == null){
                return;
            }
            String fileName = "/root/ftp/测试目录/测试.txt";
            String validFileName = new String(fileName.getBytes(), StandardCharsets.ISO_8859_1);
            boolean flag ;
            try {
                flag = ftpClient.deleteFile(validFileName);
                System.out.println("文件删除结果:"+flag);
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                ftpUtil.logoutAndDisconnect(ftpClient);
            }
        }


        /**
         * 写文件
         */
        public void writeFile(){
            FtpUtil ftpUtil = new FtpUtil();
            FTPClient ftpClient = ftpUtil.connectAndLogin();
            if(ftpClient == null){
                return;
            }

            String content = "写入ftp服务器上文件内容";
            String validFileName = new String(ftpFilePath.getBytes(),StandardCharsets.ISO_8859_1);
            //将content转为输入流
            ByteArrayInputStream is = new ByteArrayInputStream(content.getBytes());
            try {
                boolean flag =  ftpClient.storeFile(validFileName,is);
                System.out.println("写文件至ftp"+(flag?"成功":"失败"));
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                ftpUtil.logoutAndDisconnect(ftpClient);
            }

        }

        /**
         * 读文件
         */
        public void readFile(){
            FtpUtil ftpUtil = new FtpUtil();
            FTPClient ftpClient = ftpUtil.connectAndLogin();
            if(ftpClient == null){
                return;
            }
            String validFileName = new String(ftpFilePath.getBytes(), StandardCharsets.ISO_8859_1);
            try {
                if(!isFileExist(ftpFilePath,ftpClient)){
                    System.out.println("文件不存在");
                    return;
                }
                InputStream inputStream = ftpClient.retrieveFileStream(validFileName);
                //将输入流转为字符串
                InputStreamReader reader = new InputStreamReader(inputStream);
                BufferedReader bufferedReader = new BufferedReader(reader);
                String line;
                System.out.println("读取文件内容为:");
                while ((line = bufferedReader.readLine()) !=null){
                    //文件内容
                    System.out.println(line);
                }

            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                ftpUtil.logoutAndDisconnect(ftpClient);
            }
        }
}

解决办法:

一般我们使用 Xftp 或 FileZilla这些软件去连接服务器(FTP/SFTP)都是可以连接到。区别就是连接的参数中

1.协议:ftp 或 sftp

2.端口:21/22

但是在Java后台使用org.apache.commons.net.ftp.FTPClient通过协议SSH2进行SFTP连接时就会报如上错误,原因是它不支持这种方式的连接(使用FTPSClient的SSL也是不行的)。

解决方法有两种:

第一种:Java后台继续使用org.apache.commons.net.ftp.FTPClient工具,然后把服务器开启FTP协议。

第二种:换一种连接方式,使用 com.jcraft.jsch.ChannelSftp 代替org.apache.commons.net.ftp.FTPClient。

<!-- sftp -->
<dependency>
    <groupId>com.jcraft</groupId>
    <artifactId>jsch</artifactId>
    <version>0.1.54</version>
</dependency>
@Slf4j
public class SftpUtil {

    @Value("${ftp.host}")
    private String server;
    @Value("${ftp.username}")
    private String loginName;
    @Value("${ftp.password}")
    private String loginPassword;
    private Integer port = 22;

    public static void main(String[] args) {
        SftpUtil sftpUtil = new SftpUtil();
        //上传文件
        sftpUtil.uploadFile();
        //下载文件
        sftpUtil.downloadFile("目录/文件");
        //写文件
        sftpUtil.writeFile();
        //读文件
        sftpUtil.readFile();
        //删除文件
        sftpUtil.deleteFile();
    }

    /**
     * 连接登陆远程服务器
     *
     * @return
     */
    public ChannelSftp connect()  {
        JSch jSch = new JSch();
        Session session = null;
        ChannelSftp sftp = null;
        try {
            session = jSch.getSession(loginName, server, port);
            session.setPassword(loginPassword);
            session.setConfig(this.getSshConfig());
            session.connect();

            sftp = (ChannelSftp)session.openChannel("sftp");
            sftp.connect();

            log.error("结果:"+session.equals(sftp.getSession()));
            log.info("登录成功:" + sftp.getServerVersion());

        } catch (Exception e) {
            log.error("SSH方式连接FTP服务器时有JSchException异常!",e);
            return null;
        }
        return sftp;
    }

    /**
     * 获取服务配置
     * @return
     */
    private Properties getSshConfig() {
        Properties sshConfig =  new Properties();
        sshConfig.put("StrictHostKeyChecking", "no");
        return sshConfig;
    }


    /**
     * 关闭连接
     * @param sftp
     */
    public void disconnect(ChannelSftp sftp) {
        try {
            if(sftp!=null){
                if(sftp.getSession().isConnected()){
                    sftp.getSession().disconnect();
                }
            }
        } catch (Exception e) {
            log.error("关闭与sftp服务器会话连接异常",e);
        }
    }

    /**
     * 下载远程sftp服务器文件
     *
     * @return
     */
    public void downloadFile(String remoteFilename) {
        FileOutputStream output = null;
        ChannelSftp sftp = null;
        try {
            sftp = connect();
            if(sftp == null){
                return ;
            }
            //sftp服务器上文件路径
            //String remoteFilename = "/test1/测试.txt";
            //下载至本地路径
            File localFile = new File("file.pdf");
            output = new FileOutputStream(localFile);
            sftp.get(remoteFilename, output);
            System.out.println("成功接收文件,本地路径:" + localFile.getAbsolutePath());
        } catch (Exception e) {
            log.error("接收文件异常!",e);
        } finally {
            try {
                if (null != output) {
                    output.flush();
                    output.close();
                }
                // 关闭连接
                disconnect(sftp);
            } catch (IOException e) {
                log.error("关闭文件时出错!",e);
            }
        }
    }



    /**
     * 读取远程sftp服务器文件
     *
     * @return
     */
    public void readFile() {
        InputStream in = null;
        ArrayList<String> strings = new ArrayList<>();
        ChannelSftp sftp = null;
        try {
            sftp = connect();
            if(sftp == null){
                return;
            }
            String remotePath = "/test1/";
            String remoteFilename = "测试1.txt";
            sftp.cd(remotePath);
            if(!listFiles(remotePath).contains(remoteFilename)){
                log.error("no such file");
                return;
            }
            in = sftp.get(remoteFilename);
            if (in != null) {
                BufferedReader br = new BufferedReader(new InputStreamReader(in,"utf-8"));
                String str = null;
                while ((str = br.readLine()) != null) {
                    System.out.println(str);
                }
            }else{
                log.error("in为空,不能读取。");
            }
        } catch (Exception e) {
            log.error("接收文件时异常!",e);
        }  finally {
            try {
                if(in !=null){
                    in.close();
                }
                // 关闭连接
                disconnect(sftp);
            } catch (Exception e) {
                log.error("关闭文件流时出现异常!",e);
            }
        }
    }


    /**
     * 写文件至远程sftp服务器
     *
     * @return
     */
    public void writeFile(){
        ChannelSftp sftp = null;
        ByteArrayInputStream input = null;
        try {
            sftp = connect();
            if(sftp == null){
                return;
            }
            // 更改服务器目录
            String remotePath = "/test1/";
            sftp.cd(remotePath);
            // 发送文件
            String remoteFilename = "写文件.txt";
            String content = "测试内容";
            input = new ByteArrayInputStream(content.getBytes());
            sftp.put(input, remoteFilename);
        } catch (Exception e) {
            log.error("发送文件时有异常!",e);
        } finally {
            try {
                if (null != input) {
                    input.close();
                }
                // 关闭连接
                disconnect(sftp);
            } catch (Exception e) {
                log.error("关闭文件时出错!",e);
            }
        }
    }



    /**
     * 上传文件至sftp服务器
     * @return
     */
    public void uploadFile() {
        FileInputStream fis = null;
        ChannelSftp sftp = null;
        // 上传文件至服务器此目录
        String remotePath = "./file/sftp/从sftp服务器上下载.txt";
        String remoteFilename = "/test1/上传至sftp服务器.txt";
        try {
            sftp = connect();
            if(sftp == null){
                return ;
            }

            File localFile = new File(remotePath);
            fis = new FileInputStream(localFile);
            //发送文件
            sftp.put(fis, remoteFilename);
            log.info("成功上传文件" );
        } catch (Exception e) {
            log.error("上传文件时异常!",e);
        } finally {
            try {
                if (fis != null) {
                    fis.close();
                }
                // 关闭连接
                disconnect(sftp);
            } catch (Exception e) {
                log.error("关闭文件时出错!",e);
            }
        }
    }


    /**
     * 遍历远程文件
     *
     * @param remotePath
     * @return
     * @throws Exception
     */
    public List<String> listFiles(String remotePath){
        List<String> ftpFileNameList = new ArrayList<String>();
        ChannelSftp.LsEntry isEntity = null;
        String fileName = null;
        ChannelSftp sftp = null;
        try{
            sftp = connect();
            if(sftp == null){
                return null;
            }
            Vector<ChannelSftp.LsEntry> sftpFile = sftp.ls(remotePath);
            Iterator<ChannelSftp.LsEntry> sftpFileNames = sftpFile.iterator();
            while (sftpFileNames.hasNext()) {
                isEntity = (ChannelSftp.LsEntry) sftpFileNames.next();
                fileName = isEntity.getFilename();
                ftpFileNameList.add(fileName);
            }
            return ftpFileNameList;
        }catch (Exception e){
            log.error("遍历查询sftp服务器上文件异常",e);
            return null;
        }finally {
            disconnect(sftp);
        }

    }


    /**
     * 删除远程文件
     * @return
     */
    public void deleteFile() {
        boolean success = false;
        ChannelSftp sftp = null;
        try {
            sftp = connect();
            if(sftp == null){
                return;
            }
            String remotePath = "/test1/";
            String remoteFilename = "limit.lua";
            // 更改服务器目录
            sftp.cd(remotePath);
            //判断文件是否存在
            if(listFiles(remotePath).contains(remoteFilename)){
                // 删除文件
                sftp.rm(remoteFilename);
                log.info("删除远程文件" + remoteFilename + "成功!");
            }

        } catch (Exception e) {
            log.error("删除文件时有异常!",e);
        } finally {
            // 关闭连接
            disconnect(sftp);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值