今天通过FTPClient上传文件时出现,虽然无错误出现但是上传到服务器端的文件大小为0。
如图:
之前的代码:
//FTP文件上传 public static boolean upload(String hostname, int port, String username, String password, String targetPath, String fileName, InputStream inputStream) throws SocketException, IOException { //实例化ftpClient FTPClient ftpClient = new FTPClient(); //设置登陆超时时间,默认是20s ftpClient.setDataTimeout(12000); //1.连接服务器 ftpClient.connect(hostname, port); //2.登录(指定用户名和密码) boolean b = ftpClient.login(username, password); if (!b) { log.info("ftp登陸超時"); if (ftpClient.isConnected()) { // 断开连接 ftpClient.disconnect(); } } log.info("ftp登陸成功"); // 设置字符编码 ftpClient.setControlEncoding("UTF-8"); //基本路径,一定存在 String[] pathArray = targetPath.split("/"); for (String path : pathArray) { if (path.equals("")) { continue; } //3.指定目录 返回布尔类型 true表示该目录存在 boolean dirExsists = ftpClient.changeWorkingDirectory(path); //4.如果指定的目录不存在,则创建目录 if (!dirExsists) { //此方式,每次,只能创建一级目录 boolean flag = ftpClient.makeDirectory(path); if (!flag) { System.out.println("文件目录创建失败!"); return false; } ftpClient.changeWorkingDirectory(path); } } log.info("重新指定上传文件的路径:" + targetPath); //重新指定上传文件的路径 // ftpClient.changeWorkingDirectory(targetPath); //5.设置上传文件的方式 ftpClient.setBufferSize(1024 * 1024 * 10); ftpClient.setFileType(FTP.BINARY_FILE_TYPE); ftpClient.enterLocalPassiveMode(); /** * 6.执行上传 * remote 上传服务后,文件的名称 * local 文件输入流 * 上传文件时,如果已经存在同名文件,会被覆盖 */ boolean uploadFlag = false; try { uploadFlag = ftpClient.storeFile(fileName, inputStream); } catch (Exception e) { e.printStackTrace(); } finally { ftpClient.logout(); ftpClient.disconnect(); } if (uploadFlag) { System.out.println("上传成功!"); return true; } return false; }
打上断点debug,当运行到
uploadFlag = ftpClient.storeFile(fileName, inputStream);
就卡着不到,也不报错。
百度到很多都说要设置为被动模式,要加:
ftpClient.enterLocalPassiveMode();
但是我明明已经加了还是不行。
于是各种找方法,终于知道问题在哪里了,原来 ftpClient.enterLocalPassiveMode();加的地方不对,要加在建立连接和登录之间才可以。
现在的代码:
//FTP文件上传 public static boolean upload(String hostname, int port, String username, String password, String targetPath, String fileName, InputStream inputStream) throws SocketException, IOException { //实例化ftpClient FTPClient ftpClient = new FTPClient(); //设置登陆超时时间,默认是20s ftpClient.setDataTimeout(12000); //1.连接服务器 ftpClient.connect(hostname, port); ftpClient.enterLocalPassiveMode(); //2.登录(指定用户名和密码) boolean b = ftpClient.login(username, password); if (!b) { log.info("ftp登陸超時"); if (ftpClient.isConnected()) { // 断开连接 ftpClient.disconnect(); } } log.info("ftp登陸成功"); // 设置字符编码 ftpClient.setControlEncoding("UTF-8"); //基本路径,一定存在 String[] pathArray = targetPath.split("/"); for (String path : pathArray) { if (path.equals("")) { continue; } //3.指定目录 返回布尔类型 true表示该目录存在 boolean dirExsists = ftpClient.changeWorkingDirectory(path); //4.如果指定的目录不存在,则创建目录 if (!dirExsists) { //此方式,每次,只能创建一级目录 boolean flag = ftpClient.makeDirectory(path); if (!flag) { System.out.println("文件目录创建失败!"); return false; } ftpClient.changeWorkingDirectory(path); } } log.info("重新指定上传文件的路径:" + targetPath); //重新指定上传文件的路径 // ftpClient.changeWorkingDirectory(targetPath); //5.设置上传文件的方式 ftpClient.setBufferSize(1024 * 1024 * 10); ftpClient.setFileType(FTP.BINARY_FILE_TYPE); /** * 6.执行上传 * remote 上传服务后,文件的名称 * local 文件输入流 * 上传文件时,如果已经存在同名文件,会被覆盖 */ boolean uploadFlag = false; try { uploadFlag = ftpClient.storeFile(fileName, inputStream); } catch (Exception e) { e.printStackTrace(); } finally { ftpClient.logout(); ftpClient.disconnect(); } if (uploadFlag) { System.out.println("上传成功!"); return true; } return false; }
问题解决,记录一下爬坑的过程,顺便希望能帮到其他人。
顺便记录下ftp文件下载
/** * 文件下载--FTP服务器 */ @LogRecord(name = "文件下载--FTP服务器") @GetMapping(value = "/v1/zdyl/downloadFile") public ResultJson downloadFileFtp(HttpServletRequest request, HttpServletResponse response) throws Exception { String url = request.getParameter("url"); if (url == null) throw new RRException("url is Empty!"); URI uri = new URI(url); log.info("url:" + url); String path = uri.getPath(); log.info("path:" + path); InputStream inputStream = UploadUtil.downloadFile(ftpConfig.getHost(), ftpConfig.getPort(), ftpConfig.getUsername(), ftpConfig.getPassword(), path); log.info("fileName:" + path.substring(path.lastIndexOf("/") + 1)); response.setContentType("application/force-download"); response.addHeader("Content-disposition", "attachment;fileName=" + path.substring(path.lastIndexOf("/") + 1)); OutputStream os = response.getOutputStream(); byte[] buf = new byte[1024]; int len = 0; while ((len = inputStream.read(buf)) != -1) { os.write(buf, 0, len); } return null; }
/** * 功能:根据文件名称,下载文件流 * * @return * @throws IOException */ public static InputStream downloadFile(String hostname, int port, String username, String password, String remoteFilePath) throws IOException { InputStream in = null; FTPClient ftpClient = null; try { //实例化ftpClient ftpClient = new FTPClient(); //设置登陆超时时间,默认是20s ftpClient.setDataTimeout(12000); //1.连接服务器 ftpClient.connect(hostname, port); ftpClient.enterLocalPassiveMode(); //2.登录(指定用户名和密码) boolean b = ftpClient.login(username, password); if (!b) { log.info("登陸超時"); if (ftpClient.isConnected()) { // 断开连接 ftpClient.disconnect(); } } log.info("登陸成功"); // 设置字符编码 ftpClient.setControlEncoding("UTF-8"); // 设置传输二进制文件 ftpClient.setBufferSize(1024 * 1024 * 10); ftpClient.setFileType(FTP.BINARY_FILE_TYPE); int reply = ftpClient.getReplyCode(); if (!FTPReply.isPositiveCompletion(reply)) { ftpClient.disconnect(); throw new RRException("failed to connect to the FTP Server:"); } // ftp文件获取文件 in = ftpClient.retrieveFileStream(encodingPath(remoteFilePath)); } catch (FTPConnectionClosedException e) { log.error("ftp连接被关闭!", e); throw e; } catch (Exception e) { log.error("ERR : upload file " + remoteFilePath + " from ftp : failed!", e); throw new RRException("ERR : upload file " + remoteFilePath + " from ftp : failed!"); } finally { ftpClient.disconnect(); } return in; } /** * 编码文件路径 */ private static String encodingPath(String path) throws UnsupportedEncodingException { // FTP协议里面,规定文件名编码为iso-8859-1,所以目录名或文件名需要转码 return new String(path.replaceAll("//", "/").getBytes("GBK"), "iso-8859-1"); }