今天通過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"); }