用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); } } }