java版 sftp上传文件,服务器上判断文件或者目录是否存在。

本文介绍了一个使用Java实现的SFTP文件上传示例代码,该示例展示了如何通过JSch库连接SFTP服务器并自动创建多级目录进行文件上传。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

package sftp;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Vector;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpATTRS;
import com.jcraft.jsch.SftpException;
/**
 * 将目标路径化为数组,循环判断是否能进入目录;
 * 1、能进入:进入目录,继续循环
 * 2、不能进入:创建目录,继续循环
 *
 * @author Administrator
 *
 */
public class SftpUpload {
    Channel channel = null;
    Session session = null;
    public static void main(String[] args) {
        SftpUpload sft = new SftpUpload();
        Date date = new Date();
        //源文件路径
        String src = "C:\\Users\\Administrator\\Desktop\\看--不--见--我.txt";
        //目标路径
        String dst = "G:\\110-ftp\\110";
        //根路径
        String  root_dst ="G:\\110-ftp";
        sft.getChannel("127.0.0.1", 22, "root", "root", src, dst,root_dst, date);
    }
    /**
     * 进入指定目录上传文件
     * @param ip  ip地址
     * @param port  端口
     * @param userName 用户名
     * @param passWord 密码
     * @param src  源文件
     * @param dst  目标文件
     * @param root_dst 根路径
     * @param date 当前日期
     */
    @SuppressWarnings({ "rawtypes", "unused" })
    public void getChannel(String ip,int port,String userName,String passWord,String src,String dst,String root_dst,Date date){
        // 创建JSch对象
        JSch jsch = new JSch();
        // 根据用户名,主机ip,端口获取一个Session对象
        try {
            session = jsch.getSession(userName, ip, port);
            if (passWord != null) {
                // 设置密码
                session.setPassword(passWord);
            }
            java.util.Properties config = new java.util.Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);
            // 通过Session建立链接
            session.connect();
            // 打开SFTP通道
            channel = session.openChannel("sftp");
            // 建立SFTP通道的连接
            channel.connect();
        } catch (JSchException e) {
            e.printStackTrace();
        }
        ChannelSftp chsft =  (ChannelSftp) channel;
        DateFormat df = new SimpleDateFormat("yyyyMMdd");
        String str = df.format(date);
        String dst_old = dst;
        int count = getCount(dst)-1;
        System.out.println(count+"--级目录--");
        String src_sr = src.substring(src.lastIndexOf("\\")+1);
        //自动补全目录
        switch(count) {
        case 0:
            dst+= "\\"+"upload"+"\\"+"LoanApply"+"\\"+str+"\\"+"授信编号"+"\\"+src_sr;
            break;
        case 1:
            dst+= "\\"+"LoanApply"+"\\"+str+"\\"+"授信编号"+"\\"+src_sr;
            break;
        case 2:
            dst+= "\\"+str+"\\"+"授信编号"+"\\"+src_sr;
            break;
        case 3:
            dst+= "\\"+"授信编号"+"\\"+src_sr;
            break;
        case 4:
            dst+="\\"+src_sr;
            break;
        case 5:
            break;
        }
        System.out.println(dst);
        //dst去除根路径
        String cut_dst = dst.substring(root_dst.length()+1);
        System.out.println(cut_dst);
        String dst_s = cut_dst;
           if (dst.indexOf("\\") != -1) {  
                dst_s = cut_dst.replaceAll("\\\\", "/");  
           }  
        String[] paths = dst_s.split("/");
        //是否是目录或文件
        boolean isFile = true;
        for (int i = 0; i < paths.length-1; i++) {
            String dir = paths[i];
            System.out.println(dir);
            try {
                chsft.cd(dir);
                isFile = true;
            } catch (SftpException e) {
                isFile = false;
            }
            if(isFile == false) {
                try {
                    chsft.mkdir(dir);
                    chsft.cd(dir);
                } catch (SftpException e) {
                    e.printStackTrace();
                }
            }
        }
        try {
            //上传目标文件(覆盖式)
            chsft.put(src, src_sr,ChannelSftp.OVERWRITE);
            System.out.println("执行完毕");
        } catch (SftpException e) {
            e.printStackTrace();
        }
        //关闭连接
        chsft.quit();
        try {
            closeChannel();
         } catch (Exception e) {
            e.printStackTrace();
         }
    }
    /**
     * 获取\的数量判断几级目录
     * @param dst
     * @return
     */
    public int getCount(String dst) {
        int count = 0;
        int leng = dst.length();
        String dst_d = dst.replaceAll("\\\\", "");
        count = leng-dst_d.length();
        return count;
    }
    /**
     * 关闭连接
     * @throws Exception
     */
     public void closeChannel() throws Exception {
            if (channel != null) {
                channel.disconnect();
            }
            if (session != null) {
                session.disconnect();
            }
        }
}
此方法不是很成熟、完善。
<think>好的,我现在需要帮助用户解决他们的问题:使用Java SFTP上传文件时,为什么文件会被创建在指定目录的上一层级。用户之前已经询问过如何判断远程路径是否存在,现在遇到了上传文件路径的问题。首先,我需要回忆一下SFTP上传的常见问题,尤其是路径处理相关的。 首先,用户提到上传文件出现在上一级目录,可能的原因有很多。我需要逐个分析可能的情况。首先想到的是路径拼接的问题。比如用户可能错误地构造了目标路径,比如在指定目录时没有正确添加斜杠,导致路径拼接错误。例如,如果目标目录是/path/to/dir,但用户上传时使用的路径是/path/to/dirfilename,那么可能因为没有斜杠导致路径错误,实际变成在/path/to下创建dirfilename文件或者用户可能没有正确处理相对路径,比如使用了相对路径但当前工作目录不是预期的位置。 接下来,可能需要检查用户是否正确地设置了目标路径。比如,在JSch的ChannelSftp中,使用put方法时,如果目标路径是目录是否需要以斜杠结尾?或者是否应该先切换到目标目录上传?比如,如果用户调用sftp.put(localFile, remoteDir),而remoteDir是一个目录,但上传时没有在remoteDir后面加上文件名,可能导致文件上传到上一级目录或者覆盖了目录本身? 另外,用户可能在代码中处理路径时,错误地组合了目录文件名。例如,用户可能想将文件上传到/path/to/dir/下,但实际代码中可能将目录路径和文件名分开处理时出错,导致路径不正确。例如,如果用户使用sftp.cd(remoteDir)进入目录,然后sftp.put(localFile, fileName),但可能没有成功进入目录,导致文件上传到当前目录,即上一层级。 另一个可能性是用户没有检查远程目录是否存在,直接上传,导致SFTP服务器自动将文件创建在存在的路径部分。例如,如果用户指定的路径是/path/to/nonexistent_dir/file.txt,但nonexistent_dir不存在服务器可能会抛出异常,或者可能在某些配置下将文件创建在存在的父目录中,即/path/to/file.txt。但通常SFTP不会自动创建目录,所以这种情况可能不太常见,除非用户代码中处理了异常并修改了路径。 还需要考虑JSch库的具体行为。例如,当使用ChannelSftp的put方法时,如果目标路径是一个目录是否会自动将文件放入该目录,还是需要明确指定文件名?例如,正确的做法可能是,如果目标路径是目录,则需要在路径后加上文件名,否则文件会被命名为目录名,导致覆盖目录或者,如果路径不存在是否会抛出异常? 可能用户在使用put方法时,目标路径参数没有正确包含文件名。例如,假设远程目录是/path/to/dir,用户希望将文件上传到该目录下,正确的目标路径应该是/path/to/dir/filename.txt。如果用户错误地只提供了目录路径,而没有文件名,那么JSch可能会将整个目录路径视为文件名,导致在上一级目录创建文件。例如,假设用户执行sftp.put(localFile, "/remote/dir"),而/remote/dir是一个目录,那么put方法可能会将文件命名为dir,并保存在/remote目录下,覆盖原有的dir目录,但实际可能不会覆盖,而是抛出错误。不过这可能取决于SFTP服务器的配置和库的实现。 另一个可能性是用户在使用相对路径时,当前工作目录不是预期的位置。例如,用户可能认为当前目录是/remote/dir,但实际上当前目录是/remote,导致上传文件被放在/remote下而不是子目录中。 需要进一步分析代码示例。假设用户的代码是这样的: sftp.put(localPath, remoteDir); 而remoteDir是一个目录路径,比如"/path/to/dir"。此时,put方法会将本地文件上传远程路径/path/to/dir,并且如果该路径是一个目录,可能会抛出异常,或者文件命名为dir,覆盖该目录?但实际上,这可能不会发生,因为通常无法用文件覆盖目录。正确的做法应该是remotePath是目录加上文件名,如"/path/to/dir/filename.txt"。 因此,用户可能在构造远程路径时,没有将文件名附加到目录路径后面,导致目标路径被当作文件名,从而文件被创建在目录的上一级。例如,用户想要上传到/path/to/dir,但代码中remotePath设为该目录,而不是目录文件名,导致文件被命名为dir,保存在/path/to下。 所以,总结可能的原因: 1. 目标路径错误,未包含文件名,导致文件被创建到上一级目录。 2. 路径拼接错误,比如缺少斜杠,导致路径解析错误。 3. 未正确切换工作目录,导致相对路径的基准目录不正确。 4. 未检查目录是否存在,导致文件上传存在的父目录。 接下来,我需要整理这些可能性,并给出对应的解决方案。例如,确保目标路径包含完整的路径和文件名,正确使用绝对路径,检查目录是否存在,必要时创建目录,以及正确处理路径拼接时的斜杠问题。 此外,可能需要提供代码示例,说明正确的上传方式,比如如何正确构造目标路径,如何确保目录存在,如何使用绝对路径等。同时提醒用户注意路径中的斜杠,避免拼接错误,比如使用File.separator或者确保使用正斜杠,因为SFTP通常使用Unix风格的路径分隔符。 还需要考虑用户是否在使用某些框架或工具,导致路径处理出现偏差,但假设用户是直接使用JSch库的话,可能需要检查他们的路径构造逻辑。 最后,可能需要建议用户调试代码,打印出实际使用的远程路径,确认是否符合预期,以帮助定位问题。</think>--- ### **问题分析:SFTP上传文件到指定目录时,文件被错误创建在上一层级的原因** 使用Java SFTP上传文件时,若文件被意外创建在目标目录的**上一层级**,通常由以下原因导致: --- ### **1. 路径拼接错误** #### **典型场景** - **未正确添加文件名**:若将目标路径仅指定到目录(如 `/remote/dir`),未附加文件名,则SFTP客户端会尝试将文件命名为目录的最后一节(`dir`),导致文件出现在父目录中。 - **缺少路径分隔符**:拼接路径时未添加 `/`,导致路径解析错误。 ```java String remoteDir = "/remote/dir"; String fileName = "file.txt"; // 错误写法:路径变为 "/remote/dirfile.txt" String remotePath = remoteDir + fileName; // 正确写法:添加分隔符 String remotePath = remoteDir + "/" + fileName; ``` --- ### **2. 相对路径与绝对路径混淆** #### **问题表现** - **未使用绝对路径**:若目标路径以相对路径(如 `subdir/file.txt`)形式给出,文件可能基于SFTP会话的当前工作目录(如 `/remote`)生成,最终路径变为 `/remote/subdir/file.txt`。 - **未显式切换目录**:若未通过 `sftp.cd(remoteDir)` 切换到目标目录,直接上传文件,可能导致路径基准错误。 #### **解决方案** ```java // 确保使用绝对路径 String remotePath = "/remote/dir/file.txt"; sftp.put(localPath, remotePath); // 或显式切换目录 sftp.cd("/remote/dir"); sftp.put(localPath, "file.txt"); // 文件上传到当前目录(/remote/dir) ``` --- ### **3. 目录存在时的默认行为** #### **关键机制** - **未自动创建目录**:若目标目录存在SFTP默认**不会自动创建目录**,而是可能将文件保存到存在的最近父目录中(如 `/remote`),或直接抛出异常。 - **需手动创建目录**:上传前需检查并递归创建缺失的目录。 #### **示例代码(目录创建)** ```java public static void mkdirs(ChannelSftp sftp, String path) throws SftpException { String[] dirs = path.split("/"); String currentPath = ""; for (String dir : dirs) { if (dir.isEmpty()) continue; currentPath += "/" + dir; try { sftp.stat(currentPath); // 检查目录是否存在 } catch (SftpException e) { if (e.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) { sftp.mkdir(currentPath); // 创建缺失目录 } else { throw e; } } } } // 使用方式 mkdirs(sftp, "/remote/dir"); // 确保目录存在 sftp.put(localPath, "/remote/dir/file.txt"); ``` --- ### **4. 路径格式与转义问题** #### **潜在风险** - **特殊字符未转义**:若路径中包含空格、`#` 等特殊符号,可能导致解析错误。 - **路径分隔符不统一**:未使用 `/` 作为分隔符(如Windows风格的 `\`)。 #### **处理建议** ```java // 统一使用Unix风格分隔符,即使目标服务器为Windows String remotePath = "/remote/dir with space/file#1.txt"; sftp.put(localPath, remotePath); // SFTP协议会自动处理转义 ``` --- ### **5. 调试与验证步骤** #### **快速定位问题** 1. **打印实际路径**:在上传前输出远程路径,确认格式是否正确。 ```java System.out.println("Remote Path: " + remotePath); // 检查路径是否文件名 ``` 2. **手动验证路径**:通过SFTP客户端(如WinSCP)登录服务器,检查目标目录是否存在。 3. **捕获异常**:添加异常处理逻辑,明确错误类型。 ```java try { sftp.put(localPath, remotePath); } catch (SftpException e) { System.err.println("SFTP Error: " + e.id + " - " + e.getMessage()); } ``` --- ### **总结** - **核心原因**:路径拼接错误、未正确处理绝对路径、目录未提前创建。 - **解决关键**:显式指定完整路径(含文件名)、确保目录存在、统一使用绝对路径。 - **推荐实践**:上传前通过 `sftp.stat()` 检查目录,必要时递归创建缺失目录
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值