-
XLSX.SSF.format 是 Apache POI 库中用于处理 Excel 文件(特别是 .xlsx 格式)时,用于格式化单元格数据的一个功能。Apache POI 是一个流行的 Java 库,它提供了对 Microsoft Office 格式文件的读写能力,包括 Excel、Word 等。在 Excel 文件的处理中,XLSX.SSF.format 允许开发者根据预定义的格式字符串或自定义的格式字符串来设置单元格的显示格式。基本用法在 Apache POI 中,XSSFDataFormat 类是处理单元格数据格式的关键类。你可以通过 XSSFWorkbook 对象获取到一个 XSSFDataFormat 实例,然后使用它来获取或创建格式字符串。一旦你有了格式字符串,就可以将其应用到 XSSFCellStyle 对象上,进而将该样式应用到单元格上。// 假设 workbook 是已经创建的 XSSFWorkbook 对象 XSSFDataFormat format = workbook.createDataFormat(); short formatIndex = format.getFormat("#,##0.00"); // 获取或创建格式为“#,##0.00”的索引 // 接下来,你可以将这个格式索引设置到单元格样式上 XSSFCellStyle cellStyle = workbook.createCellStyle(); cellStyle.setDataFormat(formatIndex); // 最后,将这个样式应用到单元格上 XSSFCell cell = ...; // 假设这是已经创建的单元格 cell.setCellStyle(cellStyle);格式字符串格式字符串遵循 Excel 的数字格式代码规则,这些规则允许你定义如何显示数字、日期、时间、货币等。例如:#,##0.00:表示带有千位分隔符和两位小数的数字。yyyy-mm-dd:表示日期格式为年-月-日。0.00%:表示百分比,保留两位小数。注意事项当使用 XSSFDataFormat.getFormat(String formatString) 方法时,如果传入的 formatString 已经存在于工作簿的格式列表中,则该方法会返回该格式的索引;如果不存在,则会创建一个新的格式并返回其索引。单元格的显示格式和它的实际值是分开的。即使你改变了单元格的显示格式,单元格的实际值(存储在 XSSFCell 对象中的值)也不会改变。在处理大量数据时,应谨慎使用自定义格式,因为每个自定义格式都会增加工作簿的大小。结论XLSX.SSF.format(在 Apache POI 的上下文中更准确地说是 XSSFDataFormat 和相关的格式字符串)是处理 Excel 文件中单元格数据格式的强大工具。通过它,开发者可以灵活地定义单元格的显示方式,以满足不同的数据处理和展示需求。
-
包含功能为: 1、向Ftp服务器上传文件 2、从Ftp服务器下载特定文件 3、从Ftp某个文件夹里面下载所有文件 4、远程在FTP服务器指定位置创建文件夹 5、查看FTP服务器指定目录内所有文件名 解决了FTP上传/下载文件时,文件名有中文,有特殊字符时无法上传/下载的问题。 写在前面 可以直接运行的,包含上述全部功能的代码已经上传到github上了,下载文件,配置好自己的环境即可直接使用。代码中包含详细注释以及使用方式。 github链接:https://github.com/DylanYh2/FTPClient_libcurl.git libcurl库windows下编译配置 windows系统编译libcurl库,并在visual studio2019/2022使用(win10,win11通用) libcurl c++常用操作 libcurl c++常用操作 libcurl库实现FTP远程文件操作 头文件 #pragma once #include<iostream> #include<curl/curl.h> #include<string> #include<vector> using namespace std; class FtpManage { public: FtpManage(); FtpManage(const string user, const string password, const string id); ~FtpManage(); /* *@Upload: 向Ftp服务器上传文件 * @localFilePath:所上传的文件(精确到文件名),如"D:/ggbond/123.jpg" * @remoteDirectory:上传至Ftp的目录,如"/shjr/" * @remark:将123.jpg上传到Ftp服务器的"/shjr/"目录下, */ bool Upload(const char* localFilePath, const char* remoteDirectory); /* * @Download:从Ftp服务器下载特定文件 * @remoteFilePath:所下载的文件(精确到文件名)如"/shjr/333.jpg" * @localDirectory:保存至本地目录,如"D:/ggbond/" * @remark:将FTp服务器/shjr目录下的333.jpg下载到本地D:/ggbond目录 */ bool DownloadFile(const char* remoteFilePath, const char* localDirectory); /* * @DownloadAllFiles:从Ftp某个文件夹里面下载所有文件 * @remoteFilePath:所下载的文件夹名称,如"/shjr/" * @localDirectory:保存至本地目录,如"D:/ggbond/" * @remark:将FTp服务器/shjr/目录里面下载所有文件到本地D:/ggbond/目录 */ bool DownloadAllFiles(const char* remoteFilePath, const char* localDirectory); /* * @Createdir:创建文件夹 * @directoryname:文件夹名称,可包含上级目录名,要以“/”结尾以表示目录 * 比如:"/ggbond/" */ bool Createdir(const char* directoryname); /* * @GetFilesName:提供获取FTP文件夹内所有文件名的接口 * @filepath:文件夹名称,可包含上级目录名,要以“/”结尾以表示目录 * 比如:"/ggbond/" */ const std::vector<std::string>& GetFilesName(const string filepath); private: /* * @SetURL:初始化URL */ void SetURL(); /* * @UrlEncode:把含有特殊符号的文件名进行URL编码 * @value:文件名 * @"kunkunboy## 123"这种形式是无法传入curl的,需要转换一下 */ std::string UrlEncode(const std::string& value); /* * @GEtFileNameFromPath:从路径中提取文件名并返回 * @filePath:文件完整路径 * @"D:/ggbond/123.jpg"->123.jpg */ std::string GetFileNameFromPath(const std::string& filePath); /* * @GetfilenameFromftp:获得FTP服务器上某个文件夹内所有文件名,如果文件夹内既有文件又有文件夹,则只会显示文件 * @directoryname:文件夹名称,可包含上级目录名,要以“/”结尾以表示目录 */ bool GetfilenameFromftp(const string directoryname); private: std::string Ftp_ip; //Ftp服务器地址 std::string User, Password; //登录用户名及密码 std::string _URL; std::vector<std::string> fNs; //用于记录全部文件名 CURL* curl; }; 向Ftp服务器上传文件 核心代码为: /* *@Upload: 向Ftp服务器上传文件 * @localFilePath:所上传的文件(精确到文件名),如"D:/ggbond/123.jpg" * @remoteDirectory:上传至Ftp的目录,如"/shjr/" * @remark:将123.jpg上传到Ftp服务器的"/shjr/"目录下, */ bool Upload(const char* localFilePath, const char* remoteDirectory); { SetURL(); _URL = Ftp_ip + remoteDirectory+ GetFileNameFromPath(localFilePath); curl_easy_setopt(curl, CURLOPT_URL, _URL.c_str()); // 设置访问的FTP地址 if (curl) { FILE* fp = fopen(localFilePath, "rb"); curl_off_t fsize = 0; if (fp) { fseek(fp, 0, SEEK_END); fsize = ftell(fp); // 获取文件大小 fseek(fp, 0, SEEK_SET); curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); // 指定为上传文件模式 curl_easy_setopt(curl, CURLOPT_READDATA, fp); // 指定上传的文件是哪个 curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, fsize);// 指定上传的文件大小 CURLcode res = curl_easy_perform(curl); // 开始上传 if (res != CURLE_OK) { std::cout << "localFilePath: " << localFilePath << " upload failed!" << curl_easy_strerror(res) << std::endl; curl_easy_cleanup(curl); fclose(fp); return false; } else { std::cout << "localFilePath: " << localFilePath << " upload successfully!" << std::endl; } fclose(fp); } else { std::cout << "file: " << localFilePath << " open failed!" << std::endl; curl_easy_cleanup(curl); return false; } } curl_easy_cleanup(curl); return true; } 从Ftp服务器下载指定文件 核心代码为: /* * @Download:从Ftp服务器下载特定文件 * @remoteFilePath:所下载的文件(精确到文件名)如"/shjr/333.jpg" * @localDirectory:保存至本地目录,如"D:/ggbond/" * @remark:将FTp服务器/shjr目录下的333.jpg下载到本地D:/ggbond目录 */ bool FtpManage::DownloadFile(const char* remoteFilePath, const char* localDirectory) { SetURL(); _URL = Ftp_ip + UrlEncode(remoteFilePath); curl_easy_setopt(curl, CURLOPT_URL, _URL.c_str()); // 设置请求的URL if (curl) { FILE* fp = fopen((localDirectory + GetFileNameFromPath(remoteFilePath)).c_str(), "wb"); if (fp) { // 设置文件写入地址 curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); // 执行任务 CURLcode res = curl_easy_perform(curl); if (res != CURLE_OK) { std::cout << "DownLoad file:" << remoteFilePath << " failed! " << curl_easy_strerror(res) << std::endl; fclose(fp); curl_easy_cleanup(curl); return false; } else { std::cout << "DownLoad file:" << remoteFilePath << " successfully!" << std::endl; fclose(fp); } } else { std::cout << "file open failed!" << std::endl; curl_easy_cleanup(curl); // 清除curl return false; } } curl_easy_cleanup(curl); return true; } 从Ftp某个文件夹里面下载所有文件 /* * @DownloadAllFiles:从Ftp某个文件夹里面下载所有文件 * @remoteFilePath:所下载的文件夹名称,如"/shjr/" * @localDirectory:保存至本地目录,如"D:/ggbond/" * @remark:将FTp服务器/shjr/目录里面下载所有文件到本地D:/ggbond/目录 */ bool FtpManage::DownloadAllFiles(const char* remoteFilePath, const char* localDirectory) { if (GetfilenameFromftp(remoteFilePath)) { for (const auto& fns : fNs) { std::string filename = remoteFilePath + fns; bool res = DownloadFile(filename.c_str(), localDirectory); if (res) continue; else { return false; } } } return true; } 远程在FTP上创建文件夹 /* * @Createdir:创建文件夹 * @directoryname:文件夹名称,可包含上级目录名,要以“/”结尾以表示目录 * 比如:"/ggbond/" */ bool FtpManage::Createdir(const char* directoryname) { if (directoryname == nullptr) { std::cout << "directoryname is NULL!" << std::endl; return false; } SetURL(); _URL = Ftp_ip + UrlEncode(directoryname); curl_easy_setopt(curl, CURLOPT_URL, _URL.c_str()); // 指定url curl_easy_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS, 1L); //如果目录不存在则创建一个 CURLcode res = curl_easy_perform(curl); if (res != CURLE_OK) { std::cout << "Directory:" << directoryname << "create failed!" << curl_easy_strerror(res) << std::endl; curl_easy_cleanup(curl); // 清理curl return false; } else { std::cout << "Create directory:" << directoryname << " successfully!" << std::endl; } curl_easy_cleanup(curl); return true; } 获取FTP文件夹内所有文件名 /* * @GetFilesName:提供获取FTP文件夹内所有文件名的接口 * @filepath:文件夹名称,可包含上级目录名,要以“/”结尾以表示目录 * 比如:"/ggbond/" */ //接收消息回调函数 size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* output) { size_t totalSize = size * nmemb; output->append(static_cast<char*>(contents), totalSize); return totalSize; } // 获取ftp某个文件夹内文件名 bool FtpManage::GetfilenameFromftp(const std::string filePath) { SetURL(); std::string path = Ftp_ip + UrlEncode(filePath); std::string fileName; // 文件名列表保存位置 if (curl) { curl_easy_setopt(curl, CURLOPT_URL, path.c_str()); // 设置访问URL curl_easy_setopt(curl, CURLOPT_DIRLISTONLY, 1L); // 设置只返回文件 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &fileName); // 设置只获取文件名列表 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); // 设置get的回调函数 if (curl_easy_perform(curl) == CURLE_OK) //执行任务 { fNs.clear(); size_t startPos = 0, endPos = 0; while ((endPos = fileName.find('\n', startPos)) != std::string::npos ) { std::string name = fileName.substr(startPos, endPos - startPos-1); fNs.emplace_back(name); startPos = endPos + 1; } } } else { return false; } curl_easy_cleanup(curl); return true; } // 获取FTP文件夹内所有文件名的接口函数 const std::vector<std::string>& FtpManage::GetFilesName(const string filepath) { if (GetfilenameFromftp(filepath)) { return fNs; } else { return std::vector<std::string>(); } } 解决文件名中空格、特殊字符无法出现错误 // 对文件名进行URL编码,否则文件名中有空格,特殊符合(#^...)会出现URL错误 std::string FtpManage::UrlEncode(const std::string &value) { CURL* curl = curl_easy_init(); if (!curl) return ""; char* output = curl_easy_escape(curl, value.c_str(), value.length()); if (output) { std::string encoded(output); curl_free(output); curl_easy_cleanup(curl); return encoded; } curl_easy_cleanup(curl); return ""; } 其他相关函数 // 把带有路径的文件转换为文件名 D:/ggbond/123.jpg->123.jpg std::string FtpManage::GetFileNameFromPath(const std::string& filePath) { if (filePath == "") return filePath; //去除路径最后的空格 string retPath; size_t lastBlank = filePath.find_last_not_of(' '); if (lastBlank != std::string::npos) { retPath = filePath.substr(0, lastBlank+1); } else { return ""; } size_t lastSlashPos = retPath.find_last_of("/\\"); if (lastSlashPos != std::string::npos) { return retPath.substr(lastSlashPos + 1); } else { // 如果没有找到斜杠或反斜杠,整个路径就是文件名 return retPath; } } ———————————————— 原文链接:https://blog.csdn.net/yh_secret/article/details/140661525
-
FTP(File Transfer Protocol,文件传输协议)是一种用于在计算机网络上进行文件传输的标准协议。它定义了客户端和服务器之间的通信规则,使得用户可以通过网络上传和下载文件,以下分别是文件的下载以及上的过程。 1. 文件下载的过程 ① 建立连接 // 创建了一个名为ftpClient的FTP客户端对象 FTPClient ftpClient = new FTPClient(); // 指定文件下载的路径,通过ftp访问指定目录并下载文件 try (FileOutputStream out = new FileOutputStream("下载路径" + System.currentTimeMillis())){ // 连接ftp服务器(ftp默认的端口号为21)并验证用户名、密码 ftpClient.connect("ip地址",21); ftpClient.login("用户名", "密码"); } ② 切换至个人目录 boolean isChange = ftpClient.changeWorkingDirectory("个人目录名"); System.out.println("目录切换成功了吗?" + isChange); ③ 下载指定文件 // 设置文件的类型 ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE); // 下载文件,并确定结果 boolean isRetrieve = ftpClient.retrieveFile("待下载的文件名", out); 2. 文件上传过程 ① 连接ftp服务器并验证用户名、密码 无论是上传文件或是下载文件,第一部都需要先建立连接,因此,第一步的实现方法是相同的,不过,由于下载文件时是将读取到的文件存放至本地文件,因此采用的是文件输出流,但在文件上传过程中,是将本地文件读取至程序中并上传,因此需要定义的是文件输入流,以便读取本地文件并上传。 ② 切换目录至上传文件处 // 通过changeWorkingDirectory()方法切换目录并判断是否切换成功 boolean isChange = ftpClient.changeWorkingDirectory("目标目录名"); // 获取当前目录中的所有文件 FTPFile[] ftpFileList = ftpClient.listFiles(); // 如若没有你想上传的目录也可以自行建立一个目录 // 创建个人目录 ftpClient.makeDirectory("创建的目录名"); // 切换至新建目录 ftpClient.changeWorkingDirectory("创建的目录"); ③ 上传文件并存放 ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE); // 存文件至FTP boolean isStore = ftpClient.storeFile(System.currentTimeMillis(), 文件输入流); ———————————————— 原文链接:https://blog.csdn.net/qq_72172339/article/details/131645398
-
public void downloadFileStream(HttpServletResponse response, String path, String fileName) { OutputStream outputStream = null; FTPClient ftpClient = getFtpClient(); InputStream in = null; BufferedInputStream bis = null; try { int index = path.indexOf("/"); int index1 = path.indexOf("/", index + 2); //文件路径 去除掉ftp地址 String filePath = path.substring(index1) ftpClient.setFileType(FTP.BINARY_FILE_TYPE); // 设置文件ContentType类型,这样设置,会自动判断下载文件类型 response.setContentType("application/x-msdownload"); // 设置文件头:最后一个参数是设置下载的文件名并编码为UTF-8 response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8")); // 此句代码适用Linux的FTP服务器 String newPath = new String(fileName.getBytes("GBK"), StandardCharsets.ISO_8859_1); ftpClient.enterLocalPassiveMode(); // 设置被动模式,开通一个端口来传输数据 boolean result = existFile(filePath, ftpClient); if (result) { ftpClient.changeWorkingDirectory(path); in = ftpClient.retrieveFileStream(newPath); bis = new BufferedInputStream(in); outputStream = response.getOutputStream(); byte[] buf = new byte[1024]; int len = 0; while ((len = bis.read(buf)) > 0) { outputStream.write(buf, 0, len); } outputStream.flush(); } } catch (IOException e) { log.error("下载文件出错!", (Object) e.getStackTrace()); } finally { releaseFtpClient(ftpClient); if (null != outputStream) { try { outputStream.close(); } catch (IOException e) { log.error("关闭输出流出错!", (Object) e.getStackTrace()); } } if (bis != null) { try { bis.close(); } catch (IOException e) { e.printStackTrace(); } } if (in != null) { try { in.close(); //需要注意,在使用ftpClient.retrieveFileStream,一定要加completePendingCommand() //调用这个接口后,一定要手动close掉返回的InputStream,然后再调用completePendingCommand方法,若不是按照这个顺序,则会导致后面对FTPClient的操作都失败 ftpClient.completePendingCommand(); } catch (IOException e) { e.printStackTrace(); } } } } ———————————————— 原文链接:https://blog.csdn.net/weixin_40388298/article/details/119907061
-
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import org.apache.commons.net.ftp.FTP; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPFile; public class FtpFileTransferWithOriginalName { public static void main(String[] args) { String server = "your_server"; int port = 21; String user = "your_user"; String pass = "your_password"; // 下载文件 downloadFile(server, port, user, pass, "/remote_path/file.txt", "/local_path"); // 上传文件 uploadFile(server, port, user, pass, "/local_path/file.txt", "/remote_path"); } public static void downloadFile(String server, int port, String user, String pass, String remotePath, String localPath) { FTPClient ftpClient = new FTPClient(); try { ftpClient.connect(server, port); ftpClient.login(user, pass); ftpClient.enterLocalPassiveMode(); FTPFile[] files = ftpClient.listFiles(remotePath); if (files.length > 0) { FTPFile file = files[0]; String originalFileName = file.getName(); // 获取原文件名 File localFile = new File(localPath + File.separator + originalFileName); // 使用原文件名创建本地文件 OutputStream outputStream = new FileOutputStream(localFile); ftpClient.retrieveFile(remotePath, outputStream); outputStream.close(); } ftpClient.logout(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (ftpClient.isConnected()) { ftpClient.disconnect(); } } catch (IOException e) { e.printStackTrace(); } } } public static void uploadFile(String server, int port, String user, String pass, String localPath, String remotePath) { FTPClient ftpClient = new FTPClient(); try { ftpClient.connect(server, port); ftpClient.login(user, pass); ftpClient.enterLocalPassiveMode(); File localFile = new File(localPath); String originalFileName = localFile.getName(); // 获取原文件名 // 检查服务器端是否存在同名文件,如果存在则添加后缀避免冲突 boolean fileExists = checkFileExists(ftpClient, remotePath + File.separator + originalFileName); if (fileExists) { originalFileName = addSuffixToFileName(originalFileName); } ftpClient.storeFile(remotePath + File.separator + originalFileName, new FileInputStream(localFile)); ftpClient.logout(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (ftpClient.isConnected()) { ftpClient.disconnect(); } } catch (IOException e) { e.printStackTrace(); } } } // 检查服务器端指定路径是否存在文件 public static boolean checkFileExists(FTPClient ftpClient, String filePath) throws IOException { FTPFile[] files = ftpClient.listFiles(filePath); return files.length > 0; } // 给文件名添加后缀以避免冲突 public static String addSuffixToFileName(String fileName) { return fileName + "_new"; } } ———————————————— 原文链接:https://blog.csdn.net/hongyuxiongji/article/details/140848594
-
一、前端 1.首先创建下载文件按钮 <template slot-scope="scope"> <div class="Style_center"> <el-button @click="downloadFile(scope.row)" type="text" >下载文件</el-button> </div> </template> 2.其次编写手动触发事件 downloadFile(row){ this.axios.post("/Zlhzjbxxb/downloadFile", {wjdz:row.wjdz, wjmc:row.wjmc},{ headers: { //解决后端接收时多了一个 = 'Content-Type': 'application/json' } }).then(res => { this.$message.success("成功下载至桌面"); }) } wjdz和wjmc是要传给后端的值。后端获取到文件的FTP路径的时候,路径末尾会莫名的多一个等于(=)的符号,反正我的是出现了,把headers加上就完美解决了 二、后端 结尾处贴附后端全码 1.用Map来接收前端传过来的数据 public void downloadFile(@RequestBody Map<String,String> map) throws UnsupportedEncodingException { String wjdz = map.get("wjdz"); String wjmc = map.get("wjmc"); } 2.获取的文件路径,比如C:\Users\Administrator\Desktop,中间的 \ 符号会被转义,所以需要转义回来,其它符号的转义可以百度一下哦。 //解决文件名中间的符号被转义(如“/”被转义成%2F) wjdz = wjdz.replaceAll("%(?![0-9a-fA-F]{2})", "%2F"); String wjdzStr = URLDecoder.decode(wjdz, "UTF-8"); 3.在上传FTP文件的时候,为了防止重复的文件名在FTP服务器里出现,于是给每一个文件都设置了不同的文件编号,格式为xxx/2021-05-09/**************(*是uuid创建拼接在后面的),在FTP服务器里面下载文件的话需要找到具体的目录,然后再去下载具体的文件。接下来开始获取FTP文件的名称以及目录名 //获取第一个“/”的位置 int index = wjdzStr.indexOf("/"); //获取第二个 “/” 的位置 index = wjdzStr.indexOf("/", index + 1); //获取第二个 “/” 的位置后面的字符串 String result = wjdzStr.substring(index + 1); //获取第二个 “/” 的位置之前的字符串 String menuDz = wjdzStr.substring(0,index + 1); 通过以上方式来获取文件的目录和文件名称,result就是需要下载文件的名称,menuDz就是文件所在的FTP服务器里面的目录 4.接下来就是设置文件的保存地址了 FileOutputStream out = new FileOutputStream("C:\\Users\\Administrator\\Desktop\\" + wjmc ) 这里我是给设置到了桌面,后面的wjmc是该文件的中文名称,总不能给用户展示文件的路径吧...... 5.开始连接FTP服务器并且登录 FTPClient ftpClient = new FTPClient(); ftpClient.connect(hostName, port);//连接 ftpClient.login(userName, password);//登陆 这里的hostname是自己的IP地址,port是端口号(默认21),userName是用户名,password就是密码了,如果在yml文件里面封装的有,便可以直接调用,没有就自己手动填上去也是一样的 6.登上去之后便开始下载文件了,首先找到文件目录,然后再去下载 ftpClient.changeWorkingDirectory(menuDz);//切换目录 //下载文件( 获取FTP服务器指定目录的文件) //参数result,服务器指定文件 //参数out,本地输出流(负责下载后写入) ftpClient.setFileType(ftpClient.BINARY_FILE_TYPE); ftpClient.retrieveFile(result,out); ftpClient.setFileType这个就是用来配置文件传输形式的,默认ASCII,我们一般都是配置用二进制形式传送 7.最后最后就是退出登录和关闭连接了 ftpClient.logout();// 退出登录 ftpClient.disconnect();// 断开连接 8.接下来就是后端的全码了 @PostMapping(value = "/downloadFile") @ResponseBody public void downloadFile(@RequestBody Map<String,String> map) throws UnsupportedEncodingException { String wjdz = map.get("wjdz"); String wjmc = map.get("wjmc"); //解决文件名中间的符号被转义(如“/”被转义成%2F) wjdz = wjdz.replaceAll("%(?![0-9a-fA-F]{2})", "%2F"); String wjdzStr = URLDecoder.decode(wjdz, "UTF-8"); FTPClient ftpClient = new FTPClient(); int index = wjdzStr.indexOf("/"); //获取第一个“/”的位置 index = wjdzStr.indexOf("/", index + 1);//获取第二个 “/” 的位置 String result = wjdzStr.substring(index + 1);//获取第二个 “/” 的位置后面的字符串 String menuDz = wjdzStr.substring(0,index + 1);//获取第二个 “/” 的位置之前的字符串 try (FileOutputStream out = new FileOutputStream("C:\\Users\\Administrator\\Desktop\\" + wjmc )) { FtpUtil ftpUtil = new FtpUtil(); ftpClient.connect(ftpUtil.hostName, ftpUtil.port);//连接 ftpClient.login(ftpUtil.userName, ftpUtil.password);//登陆 ftpClient.changeWorkingDirectory(menuDz);//切换目录 //下载文件( 获取FTP服务器指定目录的文件) //参数result,服务器指定文件 //参数out,本地输出流(负责下载后写入) ftpClient.setFileType(ftpClient.BINARY_FILE_TYPE); ftpClient.retrieveFile(result,out); } catch (SocketException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { ftpClient.logout();// 退出登录 ftpClient.disconnect();// 断开连接 } catch (IOException e) { e.printStackTrace(); } } } 记录这些方便自己的同时也想能帮助一下和我遇到同样困惑的人,有什么不足或者不对的地方还望大佬们指出 ———————————————— 原文链接:https://blog.csdn.net/glacierW/article/details/130581947
-
一、FTP介绍 FTP是File Transfer Protocol(文件传输协议)的英文简称,即文件协议。用于Internet上的控制文件的双向传输。同时,它是一个应用程序(Application)。基于不同的操作系统有不同的FTP应用程序,而所有的应用程序都遵守同一种协议以传输文件。在FTP的使用中,用户经常遇到两个概念:下载(Download)和上次(Upload)。下载文件就是从远程主机拷贝文件至自己的计算机上;删除文件就是将文件从自己的计算机中拷贝至远程主机上。用Internet语言来说,用户可通过客户机程序向远程主机上传、下载文件(摘自百度百科)。 二、准备工作 1、在服务器安装FTP服务 FTP服务需要下FileZilla_Server服务安装程序,大家可以在网上搜索,也可以通过我的资源下载 点击下载 2、编写Java连接FTP源码 大家也可以通过CSDN资源下载我的源码 点击下载 三、实现步骤 1、编写FTP-Config.properties配置属性文件 FTP_IP=localhost FTP_PORT=21 FTP_USER=wangjunwei FTP_PASSWORD=wangjunwei FTP_PATH=/FTP FTP_DRIVELETTER=E: 2、编写FTPUtil读取FTP配置属性文件 /** * FTP服务地址 */ private static String FTP_IP; /** * FTP端口号 */ private static Integer FTP_PORT; /** * FTP用户名 */ private static String FTP_USER; /** * FTP密码 */ private static String FTP_PASSWORD; /** * FTP根路径 */ private static String FTP_PATH; /** * 映射盘符 */ private static String FTP_DRIVELETTER; static{ try { Properties properties = new Properties(); InputStream inputStream = FtpUtil.class.getResourceAsStream("/FTP-Config.properties"); properties.load(inputStream); FTP_IP = properties.getProperty("FTP_IP"); FTP_PORT = Integer.valueOf(properties.getProperty("FTP_PORT")); FTP_USER = properties.getProperty("FTP_USER"); FTP_PASSWORD = properties.getProperty("FTP_PASSWORD"); FTP_PATH = properties.getProperty("FTP_PATH"); FTP_DRIVELETTER = properties.getProperty("FTP_DRIVELETTER"); } catch (IOException e) { e.printStackTrace(); } } 3、连接(登录)FTP服务端获取授权 private static FTPClient ftpClient; public static FTPClient connectionFTPServer() { ftpClient = new FTPClient(); try { ftpClient.connect(FtpUtil.getFTP_IP(), FtpUtil.getFTP_PORT()); ftpClient.login(FtpUtil.getFTP_USER(), FtpUtil.getFTP_PASSWORD()); if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) { logger.info("==============未连接到FTP,用户名或密码错误================="); ftpClient.disconnect(); } else { logger.info("==============连接到FTP成功================="); } } catch (SocketException e) { e.printStackTrace(); logger.info("==============FTP的IP地址错误=============="); } catch (IOException e) { e.printStackTrace(); logger.info("==============FTP的端口错误=============="); } return ftpClient; } 4、编写文件上传、下载相关方法 /** * 切换到父目录 * * @return 切换结果 true:成功, false:失败 */ private static boolean changeToParentDir() { if (!ftpClient.isConnected()) { return false; } try { return ftpClient.changeToParentDirectory(); } catch (IOException e) { e.printStackTrace(); return false; } } /** * 改变当前目录到指定目录 * * @param dir * 目的目录 * @return 切换结果 true:成功,false:失败 */ private static boolean cd(String dir) { if (!ftpClient.isConnected()) { return false; } try { return ftpClient.changeWorkingDirectory(dir); } catch (IOException e) { e.printStackTrace(); return false; } } /** * 获取目录下所有的文件名称 * * @param filePath * 指定的目录 * @return 文件列表,或者null */ private static FTPFile[] getFileList(String filePath) { if (!ftpClient.isConnected()) { return null; } try { return ftpClient.listFiles(filePath); } catch (IOException e) { e.printStackTrace(); return null; } } /** * 切换工作目录 * * @param ftpPath * 目的目录 * @return 切换结果 */ public static boolean changeDir(String ftpPath) { if (!ftpClient.isConnected()) { return false; } try { // 将路径中的斜杠统一 char[] chars = ftpPath.toCharArray(); StringBuffer sbStr = new StringBuffer(256); for (int i = 0; i < chars.length; i++) { if ('\\' == chars[i]) { sbStr.append('/'); } else { sbStr.append(chars[i]); } } ftpPath = sbStr.toString(); if (ftpPath.indexOf('/') == -1) { // 只有一层目录 ftpClient.changeWorkingDirectory(new String(ftpPath.getBytes(), "iso-8859-1")); } else { // 多层目录循环创建 String[] paths = ftpPath.split("/"); for (int i = 0; i < paths.length; i++) { ftpClient.changeWorkingDirectory(new String(paths[i].getBytes(), "iso-8859-1")); } } return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 循环创建目录,并且创建完目录后,设置工作目录为当前创建的目录下 * * @param ftpPath * 需要创建的目录 * @return */ public static boolean mkDir(String ftpPath) { if (!ftpClient.isConnected()) { return false; } try { // 将路径中的斜杠统一 char[] chars = ftpPath.toCharArray(); StringBuffer sbStr = new StringBuffer(256); for (int i = 0; i < chars.length; i++) { if ('\\' == chars[i]) { sbStr.append('/'); } else { sbStr.append(chars[i]); } } ftpPath = sbStr.toString(); if (ftpPath.indexOf('/') == -1) { // 只有一层目录 ftpClient.makeDirectory(new String(ftpPath.getBytes(), "iso-8859-1")); ftpClient.changeWorkingDirectory(new String(ftpPath.getBytes(), "iso-8859-1")); } else { // 多层目录循环创建 String[] paths = ftpPath.split("/"); for (int i = 0; i < paths.length; i++) { ftpClient.makeDirectory(new String(paths[i].getBytes(), "iso-8859-1")); ftpClient.changeWorkingDirectory(new String(paths[i].getBytes(), "iso-8859-1")); } } return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 上传单个文件 * * @param inputStream * 单个文件流对象 * @param newFileName * 新文件名 * @param folder * 自定义保存的文件夹 * @return 上传结果 */ public static boolean uploadSingleAttachment(File file, String newFileName, String folder) { FtpUtil.connectionFTPServer(); if (!ftpClient.isConnected()) { logger.info("==============FTP服务已断开=============="); return false; } boolean result = false; if (ftpClient != null) { FileInputStream fileInputStream = null; try { fileInputStream = new FileInputStream(file); if(StringUtils.isNotEmpty(folder)){ FtpUtil.mkDir(folder); } ftpClient.setBufferSize(100000); ftpClient.setControlEncoding("utf-8"); ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE); result = ftpClient.storeFile(new String(newFileName.getBytes(), "iso-8859-1"), fileInputStream); } catch (Exception e) { FtpUtil.close(); e.printStackTrace(); return false; } finally { try { if (ftpClient.isConnected()) { FtpUtil.close(); } fileInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } return result; } /** * 上传多个文件 * * @param inputStreams * 多文件流对象数组 * @param newFileNames * 多文件名数组(与流对象数组一一对应) * @param folder * 自定义保存的文件夹 * @return 上传结果 */ public static String[] uploadBatchAttachment(File[] files , String[] newFileNames, String folder) { String[] filesSaveUrls = new String[files.length]; FtpUtil.connectionFTPServer(); if (!ftpClient.isConnected()) { logger.info("==============FTP服务已断开=============="); return null; } if (ftpClient != null) { FileInputStream fileInputStream = null; try { if(StringUtils.isNotEmpty(folder)){ FtpUtil.mkDir(folder); } for (int i = 0; i < files.length; i++) { filesSaveUrls[i] = FtpUtil.FTP_PATH; fileInputStream = new FileInputStream(files[i]); if(StringUtils.isNotEmpty(folder)){ filesSaveUrls[i] += "/"+folder; } ftpClient.setBufferSize(100000); ftpClient.setControlEncoding("utf-8"); ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE); ftpClient.storeFile(new String(newFileNames[i].getBytes(), "iso-8859-1"), fileInputStream); filesSaveUrls[i] += "/"+newFileNames[i]; } } catch (Exception e) { FtpUtil.close(); e.printStackTrace(); return null; } finally { try { if (ftpClient.isConnected()) { FtpUtil.close(); } fileInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } return filesSaveUrls; } /** * 上传单个文件 * * @param inputStreams * 多文件流对象数组 * @param newFileNames * 多文件名数组(与流对象数组一一对应) * @param folder * 自定义保存的文件夹 * @return 上传结果 */ public static String uploadSingleAttachment(MultipartFile multipartFile, String newFileName, String folder) { String filesSaveUrl = null; FtpUtil.connectionFTPServer(); if (!ftpClient.isConnected()) { logger.info("==============FTP服务已断开=============="); return null; } if (ftpClient != null) { try { if(StringUtils.isNotEmpty(folder)){ FtpUtil.mkDir(folder); } filesSaveUrl = FtpUtil.FTP_PATH; if(StringUtils.isNotEmpty(folder)){ filesSaveUrl += "/"+folder; } ftpClient.setBufferSize(100000); ftpClient.setControlEncoding("utf-8"); ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE); ftpClient.storeFile(new String(newFileName.getBytes(), "iso-8859-1"), multipartFile.getInputStream()); filesSaveUrl += "/"+newFileName; } catch (Exception e) { FtpUtil.close(); e.printStackTrace(); return null; } finally { if (ftpClient.isConnected()) { FtpUtil.close(); } } } return filesSaveUrl; } /** * 上传多个文件 * * @param inputStreams * 多文件流对象数组 * @param newFileNames * 多文件名数组(与流对象数组一一对应) * @param folder * 自定义保存的文件夹 * @return 上传结果 */ public static String[] uploadBatchAttachment(MultipartFile[] multipartFiles , String[] newFileNames, String folder) { String[] filesSaveUrls = new String[multipartFiles.length]; FtpUtil.connectionFTPServer(); if (!ftpClient.isConnected()) { logger.info("==============FTP服务已断开=============="); return null; } if (ftpClient != null) { InputStream inputStream = null; try { if(StringUtils.isNotEmpty(folder)){ FtpUtil.mkDir(folder); } for (int i = 0; i < multipartFiles.length; i++) { filesSaveUrls[i] = FtpUtil.FTP_PATH; inputStream = multipartFiles[i].getInputStream(); if(StringUtils.isNotEmpty(folder)){ filesSaveUrls[i] += "/"+folder; } ftpClient.setBufferSize(100000); ftpClient.setControlEncoding("utf-8"); ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE); ftpClient.storeFile(new String(newFileNames[i].getBytes(), "iso-8859-1"), inputStream); filesSaveUrls[i] += "/"+newFileNames[i]; } } catch (Exception e) { FtpUtil.close(); e.printStackTrace(); return null; } finally { try { if (ftpClient.isConnected()) { FtpUtil.close(); } inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } return filesSaveUrls; } /** * 根据文件url下载文件 * * @param path 被下载文件url * @return 文件流对象 * @throws IOException */ public static final InputStream downLoadFile(String path,String filaName){ FtpUtil.connectionFTPServer(); if (!ftpClient.isConnected()) { logger.info("==============FTP服务已断开=============="); return null; } ftpClient.enterLocalPassiveMode(); FtpUtil.changeDir(path); try { return ftpClient.retrieveFileStream(filaName); } catch (IOException e) { logger.info("==============获取文件异常=============="); e.printStackTrace(); return null; }finally{ if (ftpClient.isConnected()) { FtpUtil.close(); } } } /** * 返回FTP目录下的文件列表 * * @param pathName * @return */ public static String[] getFileNameList(String pathName) { if (!ftpClient.isConnected()) { return null; } try { return ftpClient.listNames(pathName); } catch (IOException e) { e.printStackTrace(); return null; } } /** * 删除FTP上的文件 * * @param ftpDirAndFileName * 路径开头不能加/,比如应该是test/filename1 * @return */ public static boolean deleteFile(String ftpDirAndFileName) { if (!ftpClient.isConnected()) { FtpUtil.connectionFTPServer(); } try { return ftpClient.deleteFile(ftpDirAndFileName); } catch (IOException e) { e.printStackTrace(); return false; } } /** * 删除FTP目录 * * @param ftpDirectory * @return */ public static boolean deleteDirectory(String ftpDirectory) { if (!ftpClient.isConnected()) { return false; } try { return ftpClient.removeDirectory(ftpDirectory); } catch (IOException e) { e.printStackTrace(); return false; } } /** * 关闭链接 */ public static void close() { try { if (ftpClient != null && ftpClient.isConnected()) { ftpClient.disconnect(); } } catch (Exception e) { e.printStackTrace(); } } ———————————————— 原文链接:https://blog.csdn.net/brianang/article/details/78727835
-
一、ftp简介 文件传输协议(File Transfer Protocol,FTP)是用于在网络上进行文件传输的一套标准协议,它工作在 OSI 模型的第七层, TCP 模型的第四层, 即应用层, 使用 TCP 传输而不是 UDP, 客户在和服务器建立连接前要经过一个“三次握手”的过程, 保证客户与服务器之间的连接是可靠的, 而且是面向连接, 为数据传输提供可靠保证。 FTP允许用户以文件操作的方式(如文件的增、删、改、查、传送等)与另一主机相互通信。然而, 用户并不真正登录到自己想要存取的计算机上面而成为完全用户, 可用FTP程序访问远程资源, 实现用户往返传输文件、目录管理以及访问电子邮件等等, 即使双方计算机可能配有不同的操作系统和文件存储方式。 1.1工作流程 在传输文件时,FTP 客户端程序先与服务器建立连接,然后向服务器发送命令。服务器收到命令后给予响应,并执行命令。FTP 协议与操作系统无关,任何操作系统上的程序只要符合 FTP 协议,就可以相互传输数据 1.2工作模式 FTP支持两种模式:Standard (PORT方式,主动方式),Passive (PASV,被动方式) 1.3传输方式 FTP的传输有两种方式:ASCII、二进制 二、windows开启ftp服务 在自己的电脑上可以开启一个ftp服务用于测试。 1:打开控制面板—>程序—>启动或关闭windows功能 找到互联网信息服务勾选其中的ftp服务器,web管理,万维网服务。 系统就会安装IIS服务管理器了,安装过程可能需要等待几分钟。 2:回到电脑桌面,右击“计算机”,点击 管理,进入计算机管理界面。在这里,我们就可以看到刚刚添加的IIS服务,接下来的操作就像我们在VPS主机上添加网站差不多的操作步骤了。选中IIS服务——>网站——>右键添加FTP站点 3:设置ftp基本信息。路径为远程连接的工作路径 选取本机的IP地址,SSL如果不涉密可以选无。 这里权限先这样设置之后再修改,点击完成即可。 保存后在此后即可看到添加的ftp服务。可以这样开启多个。 注意: 要想通过java程序连接FTP在这里我新建了一个FTP的用户,新建一个用户ftptest,密码:123456,如下所示 这里注意一定要把√取消掉确定完成新建,之后修改FTP服务器设置,添加这个特定用户。 点击创建的ftp名称—>ftp身份验证—>修改身份认证,禁止匿名身份 返回最开始的页面,添加刚才创建的用户,如果创建用户对勾选着可能添加不成功。 输入刚才新建的用户名和密码,完成 如何测试刚才新建的用户是否有效嘞有好多种方法常用的是CMD命令行和下面介绍的这种 打开我的电脑在最上面输入 ftp://+FTP之前设置的IP地址 我的是ftp://192.168.10.11/回车 输入用户和密码即可登录 注意:如果输入后弹出FTP文件夹错误,需要查看一下防火墙是否放行FTP服务器 解决方式: 1、打开防火墙,点击允许应用或功能通过Windows Defender防火墙 2、找到FTP服务器并勾选,然后点击确定 三、java连接ftp org.apache.commons.net提供了对FTP的开发,引入以下依赖 <dependency> <groupId>commons-net</groupId> <artifactId>commons-net</artifactId> <version>3.9.0</version> </dependency> 3.1ftp工具类 连接ftp服务 @Slf4j public class FtpClient { /** * FTP服务地址 */ private static String FTP_IP; /** * FTP端口号 */ private static Integer FTP_PORT; /** * FTP用户名 */ private static String FTP_USER; /** * FTP密码 */ private static String FTP_PASSWORD; /** * FTP根路径 */ private static String FTP_PATH; /** * 映射盘符 */ private static String FTP_DRIVELETTER; private static FTPClient ftpClient; static { try { // 根据该类的class文件获取到yaml文件 Yaml yaml = new Yaml(); URL resource = FtpClient.class.getClassLoader().getResource("application-dev.yml"); assert resource != null; // 把yaml文件加载到对象中 Object obj = yaml.load(new FileInputStream(resource.getFile())); // 解析对象中的属性并赋值 JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(obj)); JSONObject ftp = jsonObject.getObject("fanhai", JSONObject.class).getObject("ftp", JSONObject.class); FTP_IP = String.valueOf(ftp.get("ip")); FTP_PORT = Integer.valueOf(String.valueOf(ftp.get("port"))); FTP_USER = String.valueOf(ftp.get("username")); FTP_PASSWORD = String.valueOf(ftp.get("password")); } catch (Exception e) { e.printStackTrace(); } } public static FTPClient getFtpConnection() { ftpClient = new FTPClient(); try { //连接 ftpClient.connect(FtpClient.FTP_IP, FtpClient.FTP_PORT); //设置编码 ftpClient.setControlEncoding("UTF-8"); //设置传输文件类型 ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE); //登录 ftpClient.login(FtpClient.FTP_USER, FtpClient.FTP_PASSWORD); if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) { log.info("==============未连接到FTP,用户名或密码错误================="); //拒绝连接 ftpClient.disconnect(); } else { log.info("==============连接到FTP成功================="); } } catch (SocketException e) { e.printStackTrace(); log.info("==============FTP的IP地址错误=============="); } catch (IOException e) { e.printStackTrace(); log.info("==============FTP的端口错误=============="); } return ftpClient; } public static void closeConnect() { log.warn("关闭ftp服务器"); try { if (ftpClient != null) { ftpClient.logout(); ftpClient.disconnect(); } } catch (Exception e) { e.printStackTrace(); } } } ftp工具类,进行文件的上传、下载操作 ———————————————— 原文链接:https://blog.csdn.net/weixin_44486583/article/details/130319858
-
用java实现ftp文件上传。我使用的是commons-net-1.4.1.zip。其中包含了众多的java网络编程的工具包。 1 把commons-net-1.4.1.jar包加载到项目工程中去。 2 看如下代码: import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPReply; public class FileTool { /** * Description: 向FTP服务器上传文件 * @Version 1.0 * @param url FTP服务器hostname * @param port FTP服务器端口 * @param username FTP登录账号 * @param password FTP登录密码 * @param path FTP服务器保存目录 * @param filename 上传到FTP服务器上的文件名 * @param input 输入流 * @return 成功返回true,否则返回false * */ public static boolean uploadFile(String url,// FTP服务器hostname int port,// FTP服务器端口 String username, // FTP登录账号 String password, // FTP登录密码 String path, // FTP服务器保存目录 String filename, // 上传到FTP服务器上的文件名 InputStream input // 输入流 ){ boolean success = false; FTPClient ftp = new FTPClient(); ftp.setControlEncoding("GBK"); try { int reply; ftp.connect(url, port);// 连接FTP服务器 // 如果采用默认端口,可以使用ftp.connect(url)的方式直接连接FTP服务器 ftp.login(username, password);// 登录 reply = ftp.getReplyCode(); if (!FTPReply.isPositiveCompletion(reply)) { ftp.disconnect(); return success; } ftp.setFileType(FTPClient.BINARY_FILE_TYPE); ftp.makeDirectory(path); ftp.changeWorkingDirectory(path); ftp.storeFile(filename, input); input.close(); ftp.logout(); success = true; } catch (IOException e) { e.printStackTrace(); } finally { if (ftp.isConnected()) { try { ftp.disconnect(); } catch (IOException ioe) { } } } return success; } /** * 将本地文件上传到FTP服务器上 * */ public static void upLoadFromProduction(String url,// FTP服务器hostname int port,// FTP服务器端口 String username, // FTP登录账号 String password, // FTP登录密码 String path, // FTP服务器保存目录 String filename, // 上传到FTP服务器上的文件名 String orginfilename // 输入流文件名 ) { try { FileInputStream in = new FileInputStream(new File(orginfilename)); boolean flag = uploadFile(url, port, username, password, path,filename, in); System.out.println(flag); } catch (Exception e) { e.printStackTrace(); } } //测试 public static void main(String[] args) { upLoadFromProduction("192.168.13.32", 21, "hanshibo", "han", "韩士波测试", "hanshibo.doc", "E:/temp/H2数据库使用.doc"); } } 3 直接运行。即可把指定的文件上传到ftp服务器.有需要jar包的可以到我的资源中去下载。 结束! ———————————————— 原文链接:https://blog.csdn.net/atomcrazy/article/details/8943194
-
Java FTP 文件上传、下载与删除在现代软件开发中,文件传输是一项常见的需求。FTP(File Transfer Protocol)是一个用于在网络上进行文件传输的标准协议。在Java中,我们可以利用Apache Commons Net库来实现FTP的文件上传、下载和删除操作。本文将逐步讲解如何使用Java进行FTP操作,并提供相应的代码示例。准备工作在开始之前,我们需要引入Apache Commons Net库。在你的Java项目中添加以下依赖(如果使用Maven):登录后复制<dependency><groupId>commons-net</groupId><artifactId>commons-net</artifactId><version>3.8.0</version></dependency>FTP客户端基本操作1. 连接FTP服务器首先,我们需要连接到FTP服务器。以下代码示范了如何建立连接并登陆到FTP服务器:登录后复制import org.apache.commons.net.ftp.FTP;import org.apache.commons.net.ftp.FTPClient;import java.io.IOException;public class FTPExample {private FTPClient ftpClient;public void connect(String server, int port, String user, String password) throws IOException {ftpClient = new FTPClient();ftpClient.connect(server, port);ftpClient.login(user, password);ftpClient.enterLocalPassiveMode(); // 被动模式ftpClient.setFileType(FTP.BINARY_FILE_TYPE); // 设置二进制文件类型}}2. 文件上传文件上传是FTP操作中最常见的需求之一。我们可以使用storeFile方法将文件上传到服务器。以下是上传文件的代码示例:登录后复制import java.io.FileInputStream;import java.io.IOException;public void uploadFile(String localFilePath, String remoteFilePath) throws IOException {try (FileInputStream inputStream = new FileInputStream(localFilePath)) {boolean done = ftpClient.storeFile(remoteFilePath, inputStream);if (done) {System.out.println("File uploaded successfully.");} else {System.out.println("File upload failed.");}}}3. 文件下载与文件上传类似,下载文件可以使用retrieveFile方法。以下是下载文件的代码示例:登录后复制import java.io.FileOutputStream;public void downloadFile(String remoteFilePath, String localFilePath) throws IOException {try (FileOutputStream outputStream = new FileOutputStream(localFilePath)) {boolean done = ftpClient.retrieveFile(remoteFilePath, outputStream);if (done) {System.out.println("File downloaded successfully.");} else {System.out.println("File download failed.");}}}4. 文件删除删除文件可以通过deleteFile方法来实现。下面的示例代码演示了如何删除FTP服务器上的文件:登录后复制public void deleteFile(String remoteFilePath) throws IOException {boolean done = ftpClient.deleteFile(remoteFilePath);if (done) {System.out.println("File deleted successfully.");} else {System.out.println("File deletion failed.");}}完整示例以下是一个完整的Java FTP客户端示例,组合了上述所有操作:登录后复制public class FTPClientExample {private FTPClient ftpClient;public FTPClientExample() {ftpClient = new FTPClient();}public void connect(String server, int port, String user, String password) throws IOException {ftpClient.connect(server, port);ftpClient.login(user, password);ftpClient.enterLocalPassiveMode();ftpClient.setFileType(FTP.BINARY_FILE_TYPE);}public void uploadFile(String localFilePath, String remoteFilePath) throws IOException {try (FileInputStream inputStream = new FileInputStream(localFilePath)) {boolean done = ftpClient.storeFile(remoteFilePath, inputStream);if (done) {System.out.println("File uploaded successfully.");}}}public void downloadFile(String remoteFilePath, String localFilePath) throws IOException {try (FileOutputStream outputStream = new FileOutputStream(localFilePath)) {boolean done = ftpClient.retrieveFile(remoteFilePath, outputStream);if (done) {System.out.println("File downloaded successfully.");}}}public void deleteFile(String remoteFilePath) throws IOException {boolean done = ftpClient.deleteFile(remoteFilePath);if (done) {System.out.println("File deleted successfully.");}}public void disconnect() throws IOException {if (ftpClient.isConnected()) {ftpClient.logout();ftpClient.disconnect();}}}状态图示例我们可以使用状态图来描述FTP操作的状态变化。以下是一个简单的状态图示例,描述了文件上传、下载和删除的过程:DisconnectedConnectingConnectedUploadingUploadCompleteDownloadingDownloadCompleteDeletingDeleteCompleteDisconnecting数据统计在实际应用中,我们可能需要监控不同操作的状态,下面是用饼状图示例展示的一些简单统计数据。例如,统计在某一时间段内的文件操作:FTP 文件操作统计上传下载删除结尾通过本系列的示例代码,您可以在Java中轻松实现FTP文件的上传、下载和删除操作。在构建需要文件传输功能的应用时,掌握FTP的基本操作是非常重要的。这不仅可以帮助提高应用的处理效率,也能提升用户体验。原文链接:https://blog.51cto.com/u_16175522/11615875
-
概要 在实现网络编程时,需要了解很多协议,FTP协议就是很重要的一个,这篇文章主要写对于Java在基于FTP协议实现网络编程时的一些简单操作即工具类的一些简单应用方式,例如,文件的上传下载,寻找目录和创建等。 实现过程(操作代码和相关解释) 首先你要知道ftp的ip,路径,端口,有操作权限的账号和密码 导入jar包 导入commons-net 下载commons-net https://mvnrepository.com/artifact/commons-net/commons-net/3.6 或者 <dependency> <groupId>commons-net</groupId> <artifactId>commons-net</artifactId> <version>3.6</version> </dependency> 连接FTP服务器 String ip = "192.168.59.215"; int port = 21; String userName = "admin"; String passWord = "123456"; // 创建基于FTP协议访问文件客户端的对象 FTPClient client = new FTPClient(); try { client.connect(ip,21); client.login(userName,passWord); } catch (SocketException e1) { e1.printStackTrace(); } catch (IOException e1) { e1.printStackTrace(); } 获取当前文件夹目录 // 设置日期格式 SimpleDateFormat fmt = new SimpleDateFormat("yyyy年MM月dd日"); // 获取当前文件夹目录中的所有文件 FTPFile[] ftpFileList = client.listFiles(); for (FTPFile ftpFile : ftpFileList) { // 文件名称中包含中文乱码 String fileName = ftpFile.getName(); /** * FTP协议里面,规定文件名编码为iso-8859-1 * gb2312--编码集 **/ fileName = new String(fileName.getBytes("iso-8859-1"),"gb2312"); System.out.println("文件名称:"+fileName); Date createDate = ftpFile.getTimestamp().getTime(); System.out.println("文件创建时间:"+fmt.format(createDate)); System.out.println("文件大小:"+ftpFile.getSize()); } 查找和创建文件夹 String fileName = "FJQ_shuaizhao"; // 创建并切换至个人 Boolean ischange = ftpClient.changeWorkingDirectory(fileName); // 判断文件存在与否 if (!ischange) { // 创建文件夹 ftpClient.makeDirectory(fileName); // 切换文件夹 ftpClient.changeWorkingDirectory(fileName); }else{ ftpClient.changeWorkingDirectory(fileName); } 文件上传 try(FileInputStream in = new FileInputStream("本地文件上传路径")) { // 文件上传 ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE); // 存文件 ftpClient.storeFile(System.currentTimeMillis()+".jpg", in); } 文件下载 try(FileOutputStream out = new FileOutputStream("本地文件保存路径")) { // 下载指定格式文件-二进制格式BINARY_FILE_TYPE ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE); // 下载文件 Boolean isRetrieve = ftpClient.retrieveFile("fjq.jpg", out); System.out.println("下载成功?"+isRetrieve); } catch (IOException e) { e.printStackTrace(); } finally { try { ftpClient.disconnect(); } catch (IOException e) { e.printStackTrace(); } } 关闭连接 try { ftpClient.disconnect(); } catch (IOException e) { e.printStackTrace(); } 技术名词解释 FTP(File Transfer Protocol):是应用层的一个文件传输协议 。主要作用是在服务器和客户端之间实现文件的传输和共享。FTP协议运行在TCP连接上,保证了文件传输的可靠性。在传输时,传输双方的操作系统、磁盘文件系统类型可以不同。 FTP协议:允许TCP/IP网络上的两台计算机之间进行文件传输。而FTP服务是基于FTP协议的文件传输服务。工作时,一台计算机上运行FTP客户端应用程序,另一台计算机上需要运行FTP服务器端程序。只有拥有了FTP服务,客户端才能进行文件传输。 小结 基于Java和FTP的网络编程,一些简单的操作,对于初学者来说有一定帮助。 ———————————————— 原文链接:https://blog.csdn.net/q_qwp_p/article/details/131612866
-
清华大学出版社《Java程序员,上班那点事儿》作者:钟声——第10章《高手有多高菜鸟有多菜》部分节选。 大家也许都用过FTP上传下载工具,比如“LeapFTP”这个工具是一个很方便的FTP服务器上传下载工具,如图所示。这个工具很方便,输入用户名密码以后,就可以看到FTP服务器端的文件列表,便于进行上传与下载操作。 你是否试过自己用Java编写一个FTP的文件上传与下载应用程序? Java也可以开发出这样的程序来,并不复杂,我们先看看,利用Java的FTP类工具包制作FTP应用程序的开发是怎么做的,请看如下程序: import sun.net.*; import sun.net.ftp.*; public class FTP { public static void main(String[] args) { String server="192.168.0.12"; //输入的FTP服务器的IP地址 String user="useway"; //登录FTP服务器的用户名 String password=" !@#$%abce"; //登录FTP服务器的用户名的口令 String path="/home/useway"; //FTP服务器上的路径 try { FtpClient ftpClient=new FtpClient(); //创建FtpClient对象 ftpClient.openServer(server); //连接FTP服务器 ftpClient.login(user, password); //登录FTP服务器 if (path.length()!=0) ftpClient.cd(path); TelnetInputStream is=ftpClient.list(); int c; while ((c=is.read())!=-1) { System.out.print((char)c); } is.close(); ftpClient.closeServer();//退出FTP服务器 } catch(Exception ex){ } } } 如果你感兴趣的话,可以自己写一个这个程序,当本程序运行以后,我们看到如图所示的情况,列出了服务器端程序的目录内容。 这个程序是一个简单的得到FTP服务器端文件列表的程序,但不要误会,这个程序可称不上“网络应用层协议”程序的开发! 这个程序仅仅是利用“sun.net.*;”和“sun.net.ftp.*;”中的相关类进行的对FTP端的操作的,我们根本没有利用Java的Socket的在网络层面向FTP服务器端发送任何请求,而是通过Java提供的工具包,向服务器端发送的链接请求。 利用Java的FTP包来链接FTP服务器的好处在于我们不需要关心网络层面发送数据的具体细节,而只要调用相应的方法就行了。利用Java的FTP包来链接FTP服务器的缺点是使开发者不知道应用层协议收发的来龙去脉,搞不清楚其中原理,对底层数据的把握程度非常弱。 讲到这里有程序员会问:“那么FTP在网络层面和PC与服务器间是如何交互的呢?”,好,就给大家列出FTP协议交互过程。 请看下面的一段FTP协议交互的例子: FTP服务器: 220 (vsFTPd 2.0.1) FTP客户端: USER useway FTP服务器: 331 Please specify the password. FTP客户端: PASS !@#$%abce FTP服务器: 230 Login successful. FTP客户端: CWD /home/useway FTP服务器: 250 Directory successfully changed. FTP客户端: EPSV ALL FTP服务器: 200 EPSV ALL ok. FTP客户端: EPSV FTP服务器: 229 Entering Extended Passive Mode (|||62501|) FTP客户端: LIST FTP服务器: 150 Here comes the directory listing. FTP服务器: 226 Directory send OK. FTP客户端: QUIT FTP服务器: 221 Goodbye. 以上这段文字其实就是FTP服务器和FTP客户端之间相互交互的过程,它们之间传递信息的协议是TCP协议,互相发送的内容就是上面这段文字所写的内容。 我们下面逐步的去解释每一句话的含义: FTP服务器: 220 (vsFTPd 2.0.1) |说明:链接成功 FTP客户端: USER useway |说明:输入用户名 FTP服务器: 331 Please specify the password. |说明:请输入密码 FTP客户端: PASS !@#$%abce |说明:输入密码 FTP服务器: 230 Login successful. |说明:登录成功 FTP客户端: CWD /home/useway |说明:切换目录 FTP服务器: 250 Directory successfully changed. |说明:目录切换成功 FTP客户端: EPSV ALL |说明:为EPSV被动链接方式 FTP服务器: 200 EPSV ALL ok. |说明:OK FTP客户端: EPSV |说明:链接 FTP服务器: 229 Entering Extended Passive Mode (|||62501|) |说明:被动链接端口为62501 FTP客户端: LIST |说明:执行LIST显示文件列表 FTP服务器: 150 Here comes the directory listing. |说明:列表从62501端口被发送 FTP服务器: 226 Directory send OK. |说明:发送完成 FTP客户端: QUIT |说明:退出FTP FTP服务器: 221 Goodbye. |说明:再见 有了以上文字的内容,我们不需要任何工具也可以得到FTP文件列表了,不信你跟着我一起做一遍。 第一步:首先打开CMD进入DOS命令行模式,键入: telnet 192.168.0.1 21[回车] 说明:Telnet 到Ftp服务器的21端口。 执行该命令 大家发现什么问题了吗? 提示的内容正好就是,我们上面一段文字的第一句:220 (vsFTPd 2.0.1),这说明FTP服务器已经接受了我们的链接,已经可以进行下一步操作了。 第二步:将后面的一系列发送内容逐个键入: USER useway[回车] PASS !@#$%abce[回车] CWD /home/useway[回车] EPSV ALL[回车] EPSV[回车] 好,这回FTP服务器给出了一系列的回应,在最后给出了一个新的端口号"58143"。 第三步:再打开一个新的CMD窗口,键入: telnet 192.168.0.1 58143[ 回车 ] 注意,这次Telnet请求链接服务器的端口号是“58143”,是FTP服务器给我们的一个链接端口。链接后,窗口为空白没有任何提示,如图所示。 第四步:回到第一个CMD窗口,键入: LIST[ 回车 ] 第五步:这时候第二CMD窗口就接收到了文件列表: 第二个窗口接收到了文件列表如图所示。 第六步:退出操作 QUIT[ 回车 ] 执行完成后,失去与主机的链接。 大家看到了吧,FTP协议就是这样的一个交互过程,利用系统自带的Telnet工具也可以完成FTP的这些基本命令的操作。如果,你想用Java的Socket完成以上操作就只需要一步一步的按照上述内容发送字符串给FTP服务器端就行了。 我们下面也给出例子代码: import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; public class FTPClient{ public static void main(String[] args) throws Exception{ Socket socket = new Socket("192.168.0.1",21); InputStream is = socket.getInputStream(); OutputStream os = socket.getOutputStream(); //接收初始链接信息 byte[] buffer = new byte[100]; int length = is.read(buffer); String s = new String(buffer, 0, length); System.out.println(s); //发送用户名 String str = "USER useway\n"; os.write(str.getBytes()); //得到返回值 length = is.read(buffer); s = new String(buffer, 0, length); System.out.println(s); //发送密码 str = "PASS !@#$%abcd\n"; os.write(str.getBytes()); //得到返回值 length = is.read(buffer); s = new String(buffer, 0, length); System.out.println(s); //发送切换文件夹指令 str = "CWD /home/useway\n"; os.write(str.getBytes()); //得到返回值 length = is.read(buffer); s = new String(buffer, 0, length); System.out.println(s); //设置模式 str = "EPSV ALL\n"; os.write(str.getBytes()); //得到返回值 length = is.read(buffer); s = new String(buffer, 0, length); System.out.println(s); //得到被动监听信息 str = "EPSV\n"; os.write(str.getBytes()); //得到返回值 length = is.read(buffer); s = new String(buffer, 0, length); System.out.println(s); //取得FTP被动监听的端口号 String portlist=s.substring(s.indexOf("(|||")+4,s.indexOf("|)")); System.out.println(portlist); //实例化ShowList线程类,链接FTP被动监听端口号 ShowList sl=new ShowList(); sl.port=Integer.parseInt(portlist); sl.start(); //执行LIST命令 str = "LIST\n"; os.write(str.getBytes()); //得到返回值 length = is.read(buffer); s = new String(buffer, 0, length); System.out.println(s); //关闭链接 is.close(); os.close(); socket.close(); } } //得到被动链接信息类,这个类是多线程的 class ShowList extends Thread{ public int port=0; public void run(){ try{ Socket socket = new Socket("192.168.0.1",this.port); InputStream is = socket.getInputStream(); OutputStream os = socket.getOutputStream(); byte[] buffer = new byte[10000]; int length = is.read(buffer); String s = new String(buffer, 0, length); System.out.println(s); //关闭链接 is.close(); os.close(); socket.close(); } catch(Exception ex){ } } } 该程序运行后得到的运行结果如图所示,基本上和上面的运行效果相同吧,底层又如何,无非是将那些封装好的方法解开来运行,只要了解到了它们运行的规则,我们自己可以开发出一样的程序来 ———————————————— 原文链接:https://blog.csdn.net/weixin_33854644/article/details/85128720
-
引言 在Java开发中,文件传输协议(FTP)和安全文件传输协议(SFTP)是处理文件传输的两种常见方式。FTP是标准的网络文件传输协议,而SFTP则在FTP基础上增加了安全层(SSH),提供了更加安全的文件传输方式。本文将详细介绍如何在Java中实现与FTP和SFTP服务器的连接,并深入讲解各种函数的用法,以及如何进行二次封装,以提升代码的可复用性和可维护性。 文章目录 引言 一、Java连接FTP的实现 1. 配置与依赖 2. 基本连接与文件操作 3. 常用函数详解 4. 二次封装的工具类 二、Java连接SFTP的实现 1. 配置与依赖 2. 基本连接与文件操作 3.常用函数详解 4. 二次封装的工具类 FTP工具类的级联创建目录封装 SFTP工具类的级联创建目录封装 使用注意事项 三、Java连接FTP与SFTP的对比 1. 安全性 2. 性能 3. 支持与兼容性 四、总结与个人看法 一、Java连接FTP的实现 FTP协议(File Transfer Protocol)是一种用于在网络中传输文件的标准协议。Java提供了丰富的库来实现FTP连接,其中最常用的是Apache Commons Net库。该库提供了一个FTPClient类,简化了与FTP服务器的交互。 1. 配置与依赖 在使用FTPClient类之前,首先需要在项目中引入Apache Commons Net库的依赖。在Maven项目中,可以通过在pom.xml文件中添加以下依赖项来实现: <dependency> <groupId>commons-net</groupId> <artifactId>commons-net</artifactId> <version>3.8.0</version> </dependency> 2. 基本连接与文件操作 使用FTPClient连接到FTP服务器的基本流程如下: 创建FTPClient对象。 使用connect方法连接到FTP服务器。 使用login方法进行身份验证。 使用相应的方法执行文件操作,如上传、下载、删除文件等。 使用logout方法注销。 最后关闭连接。 以下是一个简单的示例,展示了如何连接到FTP服务器并上传文件: import org.apache.commons.net.ftp.FTP; import org.apache.commons.net.ftp.FTPClient; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; public class FTPExample { public static void main(String[] args) { FTPClient ftpClient = new FTPClient(); try { // 连接到FTP服务器 ftpClient.connect("ftp.example.com", 21); // 登录到FTP服务器 ftpClient.login("username", "password"); // 设置文件传输类型为二进制文件 ftpClient.setFileType(FTP.BINARY_FILE_TYPE); // 上传文件 try (InputStream inputStream = new FileInputStream("local/file/path")) { boolean done = ftpClient.storeFile("/remote/file/path", inputStream); if (done) { System.out.println("The file is uploaded successfully."); } } // 注销并关闭连接 ftpClient.logout(); } catch (IOException ex) { ex.printStackTrace(); } finally { try { if (ftpClient.isConnected()) { ftpClient.disconnect(); } } catch (IOException ex) { ex.printStackTrace(); } } } } 在这个示例中,ftpClient.connect用于连接FTP服务器,ftpClient.login进行身份验证,ftpClient.storeFile方法用于上传文件。需要注意的是,FTP传输的默认模式是ASCII,因此在上传二进制文件时,需要调用setFileType(FTP.BINARY_FILE_TYPE)来设置传输模式。 3. 常用函数详解 FTPClient类提供了丰富的功能,以下是一些常用的FTP操作函数: 连接与登录 connect(String hostname, int port):连接到指定的FTP服务器和端口。 login(String username, String password):使用用户名和密码登录FTP服务器。 logout():注销当前用户。 文件操作 storeFile(String remote, InputStream local):将本地文件上传到服务器。 retrieveFile(String remote, OutputStream local):从服务器下载文件到本地。 deleteFile(String pathname):删除服务器上的文件。 listFiles(String pathname):列出指定目录下的文件和子目录。 目录操作 makeDirectory(String pathname):在服务器上创建一个新目录。 removeDirectory(String pathname):删除服务器上的目录。 changeWorkingDirectory(String pathname):改变当前工作目录。 printWorkingDirectory():获取当前工作目录的路径。 连接管理 disconnect():断开与FTP服务器的连接。 isConnected():检查是否已连接到服务器。 4. 二次封装的工具类 为了提高代码的可复用性,可以将上述FTP操作封装到一个工具类中。这不仅简化了使用,还可以集中处理异常和日志记录等通用逻辑。 import org.apache.commons.net.ftp.FTP; import org.apache.commons.net.ftp.FTPClient; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class FTPUtil { private FTPClient ftpClient; public FTPUtil(String host, int port, String username, String password) throws IOException { ftpClient = new FTPClient(); ftpClient.connect(host, port); ftpClient.login(username, password); ftpClient.setFileType(FTP.BINARY_FILE_TYPE); } public boolean uploadFile(String remoteFilePath, InputStream inputStream) throws IOException { try { return ftpClient.storeFile(remoteFilePath, inputStream); } finally { inputStream.close(); } } public boolean downloadFile(String remoteFilePath, OutputStream outputStream) throws IOException { try { return ftpClient.retrieveFile(remoteFilePath, outputStream); } finally { outputStream.close(); } } public boolean deleteFile(String filePath) throws IOException { return ftpClient.deleteFile(filePath); } public void logoutAndDisconnect() throws IOException { if (ftpClient.isConnected()) { ftpClient.logout(); ftpClient.disconnect(); } } } 这个FTPUtil类提供了基本的上传、下载、删除文件功能,并封装了连接和注销逻辑,简化了FTP操作的使用。 二、Java连接SFTP的实现 SFTP(SSH File Transfer Protocol)是基于SSH协议的文件传输协议,提供了更加安全的文件传输方式。Java中实现SFTP连接通常使用JSch库,这个库由JCraft开发,用于SSH2的Java实现。 1. 配置与依赖 在使用JSch库之前,同样需要在项目中引入依赖。在Maven项目中,添加以下依赖项: <dependency> <groupId>com.jcraft</groupId> <artifactId>jsch</artifactId> <version>0.1.55</version> </dependency> 2. 基本连接与文件操作 使用JSch连接到SFTP服务器的基本流程如下: 创建JSch对象。 使用getSession方法创建会话并进行身份验证。 使用connect方法连接到SFTP服务器。 使用ChannelSftp对象执行文件操作。 关闭连接。 以下是一个简单的示例,展示了如何连接到SFTP服务器并上传文件: import com.jcraft.jsch.ChannelSftp; import com.jcraft.jsch.JSch; import com.jcraft.jsch.Session; import java.io.FileInputStream; import java.io.InputStream; import java.util.Properties; public class SFTPExample { public static void main(String[] args) { String SFTPHOST = "sftp.example.com"; int SFTPPORT = 22; String SFTPUSER = "username"; String SFTPPASS = "password"; String SFTPWORKINGDIR = "/remote/path/"; Session session = null; ChannelSftp channelSftp = null; try { JSch jsch = new JSch(); session = jsch.getSession(SFTPUSER, SFTPHOST, SFTPPORT); session.setPassword(SFTPPASS); // 配置StrictHostKeyChecking属性 Properties config = new Properties(); config.put("StrictHostKeyChecking", "no"); session.setConfig(config); session.connect(); channelSftp = (ChannelSftp) session.openChannel("sftp"); channelSftp.connect(); // 上传文件 try (InputStream inputStream = new FileInputStream("local/file/path")) { channelSftp.put(inputStream, SFTPWORKINGDIR + "fileName"); } } catch (Exception ex) { ex.printStackTrace(); } finally { if (channelSftp != null) { channelSftp.disconnect(); } if (session != null) { session.disconnect(); } } } } 在这个示例中,JSch类用于管理SSH连接和会话,ChannelSftp类用于执行具体的SFTP操作。需要注意的是,在实际开发中,StrictHostKeyChecking属性建议设置为yes以增强安全性。 3.常用函数详解 ChannelSftp类提供了丰富的功能,用于实现SFTP操作。以下是一些常用的SFTP操作函数: 连接与会话管理 connect():连接到SFTP服务器。 disconnect():断开与SFTP服务器的连接。 getSession():获取当前连接的会话(Session)。 文件操作 put(InputStream src, String dst):将本地文件上传到SFTP服务器的目标路径。 get(String src, OutputStream dst):从SFTP服务器下载文件到本地。 rm(String path):删除服务器上的文件。 ls(String path):列出指定目录下的文件和子目录。 目录操作 cd(String path):切换到指定目录。 mkdir(String path):在SFTP服务器上创建新目录。 rmdir(String path):删除SFTP服务器上的目录。 权限与属性管理 chmod(int permissions, String path):修改文件或目录的权限。 chown(int uid, String path):修改文件或目录的所有者。 chgrp(int gid, String path):修改文件或目录的所属组。 stat(String path):获取文件或目录的属性。 4. 二次封装的工具类 为了更好地管理SFTP连接和操作,实现更强大的功能,如级联创建目录和其他操作,我们可以将常用功能封装到一个工具类中,提高代码的可读性和可维护性的同时,确保可以顺利处理复杂的文件系统操作。比如级联创建目录,在级联创建目录时,我们需要逐级检查每个目录是否存在,如果不存在则创建它。这在FTP和SFTP操作中都非常常见。 FTP工具类的级联创建目录封装 import org.apache.commons.net.ftp.FTP; import org.apache.commons.net.ftp.FTPClient; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class FTPUtil { private FTPClient ftpClient; public FTPUtil(String host, int port, String username, String password) throws IOException { ftpClient = new FTPClient(); ftpClient.connect(host, port); ftpClient.login(username, password); ftpClient.setFileType(FTP.BINARY_FILE_TYPE); } // 上传文件 public boolean uploadFile(String remoteFilePath, InputStream inputStream) throws IOException { try { return ftpClient.storeFile(remoteFilePath, inputStream); } finally { inputStream.close(); } } // 下载文件 public boolean downloadFile(String remoteFilePath, OutputStream outputStream) throws IOException { try { return ftpClient.retrieveFile(remoteFilePath, outputStream); } finally { outputStream.close(); } } // 删除文件 public boolean deleteFile(String filePath) throws IOException { return ftpClient.deleteFile(filePath); } // 级联创建目录 public boolean createDirectories(String remoteDirPath) throws IOException { String[] directories = remoteDirPath.split("/"); String currentDir = ""; boolean dirExists = false; for (String dir : directories) { if (dir.isEmpty()) continue; currentDir += "/" + dir; dirExists = ftpClient.changeWorkingDirectory(currentDir); if (!dirExists) { if (!ftpClient.makeDirectory(currentDir)) { throw new IOException("Failed to create directory: " + currentDir); } ftpClient.changeWorkingDirectory(currentDir); } } return true; } // 删除目录(仅删除空目录) public boolean deleteDirectory(String directoryPath) throws IOException { return ftpClient.removeDirectory(directoryPath); } // 递归删除目录(包括子文件和子目录) public boolean deleteDirectoryRecursively(String remoteDirPath) throws IOException { FTPFile[] files = ftpClient.listFiles(remoteDirPath); for (FTPFile file : files) { String filePath = remoteDirPath + "/" + file.getName(); if (file.isDirectory()) { deleteDirectoryRecursively(filePath); } else { deleteFile(filePath); } } return deleteDirectory(remoteDirPath); } // 退出并断开连接 public void logoutAndDisconnect() throws IOException { if (ftpClient.isConnected()) { ftpClient.logout(); ftpClient.disconnect(); } } } SFTP工具类的级联创建目录封装 import com.jcraft.jsch.ChannelSftp; import com.jcraft.jsch.JSch; import com.jcraft.jsch.Session; import java.io.InputStream; import java.io.OutputStream; import java.util.Properties; import java.util.Vector; public class SFTPUtil { private ChannelSftp channelSftp; private Session session; public SFTPUtil(String host, int port, String username, String password) throws Exception { JSch jsch = new JSch(); session = jsch.getSession(username, host, port); session.setPassword(password); Properties config = new Properties(); config.put("StrictHostKeyChecking", "no"); session.setConfig(config); session.connect(); channelSftp = (ChannelSftp) session.openChannel("sftp"); channelSftp.connect(); } // 上传文件 public void uploadFile(String remoteDir, String remoteFileName, InputStream inputStream) throws Exception { channelSftp.cd(remoteDir); channelSftp.put(inputStream, remoteFileName); } // 下载文件 public void downloadFile(String remoteFilePath, OutputStream outputStream) throws Exception { channelSftp.get(remoteFilePath, outputStream); } // 删除文件 public void deleteFile(String remoteFilePath) throws Exception { channelSftp.rm(remoteFilePath); } // 级联创建目录 public void createDirectories(String remoteDirPath) throws Exception { String[] directories = remoteDirPath.split("/"); String currentDir = ""; for (String dir : directories) { if (dir.isEmpty()) continue; currentDir += "/" + dir; try { channelSftp.cd(currentDir); } catch (Exception e) { channelSftp.mkdir(currentDir); channelSftp.cd(currentDir); } } } // 删除目录(仅删除空目录) public void deleteDirectory(String remoteDir) throws Exception { channelSftp.rmdir(remoteDir); } // 递归删除目录(包括子文件和子目录) public void deleteDirectoryRecursively(String remoteDirPath) throws Exception { Vector<ChannelSftp.LsEntry> files = channelSftp.ls(remoteDirPath); for (ChannelSftp.LsEntry entry : files) { if (!entry.getFilename().equals(".") && !entry.getFilename().equals("..")) { String filePath = remoteDirPath + "/" + entry.getFilename(); if (entry.getAttrs().isDir()) { deleteDirectoryRecursively(filePath); } else { deleteFile(filePath); } } } deleteDirectory(remoteDirPath); } // 退出并断开连接 public void logoutAndDisconnect() { if (channelSftp != null) { channelSftp.disconnect(); } if (session != null) { session.disconnect(); } } } 使用注意事项 级联目录创建:在处理复杂路径时,必须确保各级目录按顺序被创建。如果操作失败,应当立即停止并报告错误。 递归删除:在删除目录时,递归删除可以确保目录及其所有内容都被彻底删除。然而,必须注意,这是一项危险操作,可能会导致数据丢失,因此在执行之前应该进行仔细确认。 异常处理:在目录操作过程中,由于路径错误、权限不足或网络问题可能导致异常,应确保这些异常被捕获并妥善处理,以避免影响系统的稳定性。 三、Java连接FTP与SFTP的对比 FTP和SFTP在实际项目中各有应用场景。FTP由于其简单性和广泛支持,适用于一些对安全性要求不高的场景;而SFTP由于具备更高的安全性和数据加密特性,更适合用于涉及敏感数据的场景。 1. 安全性 SFTP在安全性方面具有明显的优势。它通过SSH协议加密数据传输,避免了数据在传输过程中的被窃听和篡改风险。相比之下,FTP采用明文传输,容易受到中间人攻击。 2. 性能 FTP通常在速度上略优于SFTP,因为它省去了加密和解密过程。不过,在现代硬件环境下,这种性能差异通常可以忽略不计。 3. 支持与兼容性 FTP在许多系统中得到了广泛的支持,几乎所有的操作系统和许多文件管理工具都支持FTP。而SFTP的支持相对较少,但在涉及安全要求的项目中,SFTP是更合适的选择。 四、总结与个人看法 通过本文,我们深入探讨了如何在Java中实现FTP和SFTP连接,并详细介绍了相关的函数用法和二次封装工具类的实现。对于两者的应用场景和差异,我们也进行了对比分析。 个人看法:在选择FTP还是SFTP时,应该根据项目的具体需求进行权衡。如果安全性是重中之重,SFTP无疑是首选。此外,随着互联网安全要求的日益提高,FTP的应用场景可能会逐渐减少。因此,在新项目中,建议优先考虑SFTP作为文件传输的解决方案。当然,在某些内网环境或临时性项目中,FTP的简单性和较低的配置成本也使其成为一个不错的选择。在处理文件传输任务时,封装常用的操作功能,不仅可以提高代码的复用性,还能减少开发过程中的重复劳动,提升项目的开发效率。对于级联操作和递归操作,虽然实现起来相对复杂,但这些功能对于许多实际场景是必不可少的,因此在开发中应当积极采用这些封装技术,确保系统的健壮性和灵活性。 希望这篇随笔能够帮助你更好地理解和掌握Java中FTP和SFTP的实现方法,并为实际项目提供一些有价值的参考。如果你在开发过程中有任何问题或需要进一步探讨,欢迎随时交流。 ———————————————— 原文链接:https://blog.csdn.net/QWERTYwqj/article/details/141160425
-
1、Java常用的设计模式 总体来说设计模式分为三大类,共23种: (1)创建型模式,共五种: Factory(工厂模式:简单工厂模式和抽象工厂模式)、Factory Method(工厂方法模式)、Singleton(单例模式)、Builder(建造者模式)、Prototype(原始模型模式)。 (2)结构型模式,共七种: Adapter(适配器模式)、Decorator(装饰器模式)、Proxy(代理模式)、Facade(外观模式)、Bridge(桥梁模式)、Composite(组合模式)、Flyweight(享元模式)。 (3)行为型模式,共十一种: Strategy(策略模式)、Template Method(模板方法模式)、Observer(观察者模式)、Iterator(迭代子模式)、Chain Of Responsibility(责任链模式)、Command(命令模式)、Memento(备忘录模式)、State(状态模式)、Visitor(访问者模式)、Mediator(中介者模式)、Interpreter(解释器模式)。 (4)其实还有两类:并发型模式和线程池模式。 2、Java遵循的设计原则 总原则:开闭原则(Open Close Principle,OCP) 开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,而是要扩展原有代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类等。 (1)单一职责原则(Single Responsibility Principle,SRP) 不要存在多于一个导致类变更的原因,也就是说每个类应该实现单一的职责,如若不然,就应该把类拆分。 (2)里氏替换原则(Liskov Substitution Principle,LSP) 面向对象设计的基本原则之一。 里氏替换原则中说,任何父类可以出现的地方,子类一定可以出现。LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。里氏替换原则中,子类对父类的方法尽量不要重写和重载。因为父类代表了定义好的结构,通过这个规范的接口与外界交互,子类不应该随便破坏它。 (3)依赖倒转原则(Dependence Inversion Principle,DIP) 这个是开闭原则的基础,具体内容:面向接口编程,依赖于抽象而不依赖于具体。写代码时用到具体类时,不与具体类交互,而与具体类的上层接口交互。 (4)接口隔离原则(Interface Segregation Principle,ISP) 这个原则的意思是:每个接口中不应存在子类用不到却必须实现的方法,如果不然,就要将接口拆分。使用多个隔离的接口,比使用单个接口(多个接口方法集合到一个的接口)要好。 (5)迪米特原则(最少知道原则)(Law of Demeter,LOD或Least Knowledge Principle,LKP) 就是说:一个类对自己依赖的类知道的越少越好。也就是说无论被依赖的类多么复杂,都应该将逻辑封装在方法的内部,通过public方法提供给外部。这样当被依赖的类变化时,才能最小的影响该类。最少知道原则的另一个表达方式是:只与直接的朋友通信。类之间只要有耦合关系,就叫朋友关系。耦合分为依赖、关联、聚合、组合等。我们称出现为成员变量、方法参数、方法返回值中的类为直接朋友。局部变量、临时变量则不是直接的朋友。我们要求陌生的类不要作为局部变量出现在类中。 (6)合成复用原则(Composite Reuse Principle,CRP) 原则是尽量首先使用合成/聚合的方式,而不是使用继承。 ———————————————— 原文链接:https://blog.csdn.net/jsc123581/article/details/81748124
-
1.背景介绍 面向对象设计模式是一种软件设计的方法,它提供了一种抽象的方式来解决常见的软件设计问题。这种方法通过将问题分解为一组可重用的、可组合的对象来解决。这些对象可以表示实体、概念或抽象,并可以通过消息传递来交互。设计模式可以帮助程序员更快地开发高质量的软件,并提高代码的可读性、可维护性和可扩展性。 在本文中,我们将讨论23种经典的面向对象设计模式,并详细解释它们的定义、原理、优缺点和应用场景。这些设计模式可以分为三个类别:创建型模式、结构型模式和行为型模式。 2.核心概念与联系 2.1 创建型模式 创建型模式是一种用于创建对象的设计模式,它们提供了一种抽象的方式来创建对象,使得代码更加可维护和可扩展。创建型模式包括以下七种: 单例模式(Singleton) 工厂方法模式(Factory Method) 抽象工厂模式(Abstract Factory) 建造者模式(Builder) 原型模式(Prototype) 模板方法模式(Template Method) 代理模式(Proxy) 2.2 结构型模式 结构型模式是一种用于定义和组织类和对象的设计模式,它们提供了一种抽象的方式来组合类和对象,使得代码更加可维护和可扩展。结构型模式包括以下七种: 适配器模式(Adapter) 桥接模式(Bridge) 组合模式(Composite) 装饰模式(Decorator) 外观模式(Facade) 享元模式(Flyweight) 代理模式(Proxy) 2.3 行为型模式 行为型模式是一种用于定义对象之间的交互和行为的设计模式,它们提供了一种抽象的方式来描述对象之间的交互,使得代码更加可维护和可扩展。行为型模式包括以下十一种: 命令模式(Command) 策略模式(Strategy) 状态模式(State) 观察者模式(Observer) 中介模式(Mediator) 迭代子模式(Iterator) 访问者模式(Visitor) 备忘录模式(Memento) 责任链模式(Chain of Responsibility) 解释器模式(Interpreter) 3.核心算法原理和具体操作步骤以及数学模型公式详细讲解 在这个部分,我们将详细讲解每种设计模式的算法原理、具体操作步骤以及数学模型公式。由于篇幅限制,我们将只讨论其中的一部分设计模式。 3.1 单例模式 单例模式是一种创建型模式,它限制一个类只能有一个实例。这种模式通常用于管理全局资源,如数据库连接、文件输出等。 算法原理:单例模式使用一个静态变量来存储一个类的实例,并提供一个公共的静态方法来访问这个实例。当第一次访问这个方法时,它会创建一个新的实例,并将其存储在静态变量中。在后续的访问中,它会返回已存储的实例。 具体操作步骤: 在类中声明一个静态变量来存储实例。 在类中声明一个私有的构造函数,以防止外部创建新的实例。 在类中声明一个公共的静态方法,用于访问实例。 在静态方法中,检查静态变量是否已经存在实例。如果不存在,创建一个新的实例并将其存储在静态变量中。如果存在,返回已存储的实例。 数学模型公式: $$ Singleton = {S \mid \forall i,j \in S, i \neq j \Rightarrow si = sj} $$ 其中,$S$ 是单例集合,$si$ 和 $sj$ 是 $S$ 中的不同元素。 3.2 工厂方法模式 工厂方法模式是一种创建型模式,它提供了一个用于创建对象的接口,但让子类决定实例化哪个具体的类。这种模式通常用于创建不同类型的对象,而不需要知道它们的具体类。 算法原理:工厂方法模式定义了一个接口用于创建对象,并将实例化过程委托给子类。子类实现这个接口,并在其中调用具体的构造函数来创建对象。 具体操作步骤: 创建一个抽象的工厂类,包含一个用于创建对象的接口。 创建一个或多个具体的工厂类,继承抽象工厂类,并实现接口。 在具体工厂类中,实现创建对象的方法,调用具体的构造函数。 使用具体工厂类来创建对象。 数学模型公式: $$ FactoryMethod = {F \mid \forall fi \in F, fi(c) = c_i} $$ 其中,$F$ 是工厂方法集合,$fi$ 是 $F$ 中的一个方法,$c$ 是类的集合,$ci$ 是 $c$ 中的一个具体类。 4.具体代码实例和详细解释说明 在这个部分,我们将通过一个具体的代码实例来演示单例模式和工厂方法模式的使用。 4.1 单例模式 ```python class Singleton: _instance = None def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs) return cls._instance def __init__(self): self.value = 42 s1 = Singleton() s2 = Singleton() print(s1 is s2) # True ``` 在这个例子中,我们定义了一个 Singleton 类,它使用一个静态变量 _instance 来存储实例。在 __new__ 方法中,我们检查静态变量是否已经存在实例,如果不存在,创建一个新的实例并将其存储在静态变量中。如果存在,返回已存储的实例。 4.2 工厂方法模式 ```python from abc import ABC, abstractmethod class Animal(ABC): @abstractmethod def speak(self): pass class Dog(Animal): def speak(self): return "Woof!" class Cat(Animal): def speak(self): return "Meow!" class AnimalFactory: @staticmethod def createanimal(animaltype): if animaltype == "Dog": return Dog() elif animaltype == "Cat": return Cat() else: raise ValueError("Invalid animal type") dog = AnimalFactory.createanimal("Dog") cat = AnimalFactory.createanimal("Cat") print(dog.speak()) # Woof! print(cat.speak()) # Meow! ``` 在这个例子中,我们定义了一个 Animal 抽象类和两个具体的子类 Dog 和 Cat。这些类实现了一个 speak 方法,用于表示不同的动物发出的声音。我们还定义了一个 AnimalFactory 类,它包含一个静态方法 create_animal,用于根据传入的字符串创建不同类型的动物。这个方法使用了工厂方法模式,因为它提供了一个用于创建对象的接口,但让子类决定实例化哪个具体的类。 5.未来发展趋势与挑战 面向对象设计模式已经成为软件开发的一部分,它们已经广泛应用于各种类型的软件系统。未来,我们可以预见以下几个方面的发展趋势和挑战: 随着软件系统的复杂性和规模的增加,设计模式将更加重要,因为它们可以帮助我们更好地组织和管理代码。 随着编程语言和框架的发展,设计模式将更加灵活和可扩展,以适应不同的应用场景。 随着人工智能和机器学习的发展,设计模式将更加关注如何构建可扩展、可维护的机器学习模型和系统。 随着云计算和分布式系统的发展,设计模式将更加关注如何构建高性能、高可用性的分布式系统。 随着安全性和隐私问题的加剧,设计模式将更加关注如何构建安全、隐私保护的软件系统。 6.附录常见问题与解答 在这个部分,我们将回答一些常见问题: Q:设计模式是否适用于所有的软件项目? A:不适用。设计模式是一种软件设计的方法,它们可以帮助程序员更快地开发高质量的软件,并提高代码的可读性、可维护性和可扩展性。但是,在某些情况下,使用设计模式可能会导致代码过于复杂和难以理解。因此,在选择使用设计模式时,需要权衡其优缺点。 Q:设计模式是否会限制我的创造力? A:不会。设计模式是一种抽象的方式来解决常见的软件设计问题,它们可以帮助程序员更快地开发高质量的软件,并提高代码的可读性、可维护性和可扩展性。使用设计模式并不意味着限制你的创造力,而是提供了一种更高效、更结构化的方式来构建软件系统。 Q:如何选择适合的设计模式? A:选择适合的设计模式需要考虑以下几个因素: 问题的具体性:设计模式应该与问题紧密相关,不应该过度设计。 问题的复杂性:更复杂的问题可能需要多个设计模式来解决。 设计模式的可读性和可维护性:选择易于理解和维护的设计模式。 设计模式的适用性:确保选定的设计模式适用于当前的技术栈和团队能力。 Q:设计模式是否会导致代码冗余? A:可能。使用设计模式可能会导致代码冗余,因为设计模式通常包括一些重复的代码。但是,这种冗余通常是可以接受的,因为它可以提高代码的可读性、可维护性和可扩展性。在选择使用设计模式时,需要权衡其优缺点。 ———————————————— 原文链接:https://blog.csdn.net/universsky2015/article/details/137313201
上滑加载中
推荐直播
-
码道新技能,AI 新生产力——从自动视频生成到开源项目解析2026/04/08 周三 19:00-21:00
童得力-华为云开发者生态运营总监/何文强-无人机企业AI提效负责人
本次华为云码道 Skill 实战活动,聚焦两大 AI 开发场景:通过实战教学,带你打造 AI 编程自动生成视频 Skill,并实现对 GitHub 热门开源项目的智能知识抽取,手把手掌握 Skill 开发全流程,用 AI 提升研发效率与内容生产力。
回顾中 -
华为云码道:零代码股票智能决策平台全功能实战2026/04/18 周六 10:00-12:00
秦拳德-中软国际教育卓越研究院研究员、华为云金牌讲师、云原生技术专家
利用Tushare接口获取实时行情数据,采用Transformer算法进行时序预测与涨跌分析,并集成DeepSeek API提供智能解读。同时,项目深度结合华为云CodeArts(码道)的代码智能体能力,实现代码一键推送至云端代码仓库,建立起高效、可协作的团队开发新范式。开发者可快速上手,从零打造功能完整的个股筛选、智能分析与风险管控产品。
回顾中 -
华为云码道全新升级,多会话并行与多智能体协作2026/05/08 周五 19:00-21:00
王一男-华为云码道产品专家;张嘉冉-华为云码道工程师;胡琦-华为云HCDE;程诗杰-华为云HCDG
华为云码道4月份版本全新升级,此次直播深度解读4月份产品特性,通过“特性解读+实操演示+实战案例+设计创新”的组合,全方位展现码道在多会话并行与多智能体协作方面的能力,赋能开发者提升效率
正在直播
热门标签