Java应用Excel文件从Unix服务器通过ChannelSftp下载至Windows客户端失败求助
问题:Java SFTP下载文件到客户端本地失败,文件反而创建在服务器端
我近期用Java开发了一个应用,用来处理API并生成Excel文件。这个应用的JAR包部署在Unix服务器上,由Windows客户端发起请求触发运行。现在的问题是:应用已经能在服务器上成功生成Excel文件,但尝试用ChannelSftp下载文件到本地客户端时,文件却被创建在了服务器的JAR包目录下,而不是客户端的本地(生成的文件路径是C:\Users\PFName-CFName_Co.xlsx)。
下面是相关的代码片段,恳请帮忙排查怎么把文件下载到客户端C盘的任意位置:
String SerDir=System.getProperty("user.home") + "/Desktop/"; String LocDir="C:\Users"; String SerFC = SerDir+PFName+"-"+CFName+"_Co.xlsx"; String LocFC = LocDir+PFName+"-"+CFName+"_Cos.xlsx"; Session session = null; ChannelSftp sftpChannel=null; Channel channel = null; JSch jsch = new JSch(); try { session = jsch.getSession(username, hostname, 22); session.setConfig("StrictHostKeyChecking","no"); session.setPassword(password); Properties config = new Properties(); config.put("StrictHostKeyChecking", "no"); session.setConfig(config); session.connect(); channel = session.openChannel("sftp"); channel.connect(); sftpChannel =(ChannelSftp) channel; sftpChannel.cd(SerDir); File file = new File(SerFC); byte[] buffer = new byte[1024]; BufferedInputStream bis; bis = new BufferedInputStream(sftpChannel.get(file.getName())); File newFile = new File(LocDir + file.getName()); // Download file OutputStream os = new FileOutputStream(newFile); BufferedOutputStream bos = new BufferedOutputStream(os); int readCount; while ((readCount = bis.read(buffer)) > 0) { bos.write(buffer, 0, readCount); } bis.close(); bos.close();
解答
兄弟,问题的核心其实一眼就能看出来——你搞反了代码的运行环境和SFTP的传输方向!
咱们拆解下问题:
- 你的JAR包是跑在Unix服务器上的,Windows客户端只是发请求触发它运行。那代码里的
File newFile = new File(...)和FileOutputStream都是在服务器的JVM里执行的,Unix系统根本不存在C:\Users这种Windows路径,它会把这个路径当成相对路径解析,最后文件自然就落到服务器的JAR目录附近了。 - 另外你用SFTP的逻辑也错了:当前代码是让服务器通过SFTP连接到某个主机拉文件,而不是把服务器生成的Excel推给Windows客户端。
针对你的场景,有两种靠谱的解决办法,看你客户端的类型:
场景一:客户端是Web浏览器/HTTP接口调用
如果是通过HTTP请求触发服务器生成Excel,完全不用折腾SFTP,直接把文件作为HTTP响应返回给客户端就行,浏览器会自动弹出下载选项让用户选择本地保存路径:
// 服务器端接口里生成Excel后,添加这段代码返回文件 File excelFile = new File(SerFC); // 设置响应头,告诉浏览器这是Excel文件 response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setHeader("Content-Disposition", "attachment; filename=\"" + excelFile.getName() + "\""); // 把文件内容写入响应输出流 try (InputStream in = new FileInputStream(excelFile); OutputStream out = response.getOutputStream()) { byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = in.read(buffer)) != -1) { out.write(buffer, 0, bytesRead); } }
场景二:客户端是独立的Java程序
如果客户端是单独的Java程序,那SFTP的代码必须写在客户端,而不是服务器端:
- 服务器只负责生成Excel,存在服务器的固定目录(比如
/home/xxx/Desktop/) - 客户端运行SFTP代码,主动连接到Unix服务器,把文件拉到自己的
C:\Users目录下
客户端示例代码如下:
// 这段代码在Windows客户端运行 String serverHost = "你的Unix服务器IP"; String serverUser = "服务器登录用户名"; String serverPass = "服务器登录密码"; // 服务器上Excel文件的绝对路径 String serverFilePath = "/home/xxx/Desktop/" + PFName + "-" + CFName + "_Co.xlsx"; // 客户端本地保存路径,注意反斜杠要转义 String localFilePath = "C:\\Users\\" + PFName + "-" + CFName + "_Co.xlsx"; JSch jsch = new JSch(); Session session = jsch.getSession(serverUser, serverHost, 22); session.setPassword(serverPass); // 跳过主机密钥检查(测试环境用,生产环境建议配置密钥) Properties config = new Properties(); config.put("StrictHostKeyChecking", "no"); session.setConfig(config); session.connect(); // 打开SFTP通道 ChannelSftp sftpChannel = (ChannelSftp) session.openChannel("sftp"); sftpChannel.connect(); // 从服务器下载文件到本地 sftpChannel.get(serverFilePath, localFilePath); // 关闭资源 sftpChannel.disconnect(); session.disconnect();
额外小提醒
- 你原来代码里的
LocDir="C:\Users"少了反斜杠转义,应该写成"C:\\Users",不过这不是核心问题 - 如果是Web场景,优先用HTTP返回文件的方案,比SFTP简单太多
- 用SFTP时一定要搞清楚谁是发起方:要拉文件的是客户端,所以代码写在客户端;要推文件的是服务器,才在服务器写推送逻辑
内容的提问来源于stack exchange,提问作者Kiran Kumar Thimmegowda




