You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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的传输方向

咱们拆解下问题:

  1. 你的JAR包是跑在Unix服务器上的,Windows客户端只是发请求触发它运行。那代码里的File newFile = new File(...)FileOutputStream都是在服务器的JVM里执行的,Unix系统根本不存在C:\Users这种Windows路径,它会把这个路径当成相对路径解析,最后文件自然就落到服务器的JAR目录附近了。
  2. 另外你用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

火山引擎 最新活动