惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
The Exploit Database - CXSecurity.com
V
Vulnerabilities – Threatpost
Google DeepMind News
Google DeepMind News
Attack and Defense Labs
Attack and Defense Labs
Webroot Blog
Webroot Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
TaoSecurity Blog
TaoSecurity Blog
I
Intezer
Application and Cybersecurity Blog
Application and Cybersecurity Blog
N
News | PayPal Newsroom
S
Security Affairs
T
Tor Project blog
P
Proofpoint News Feed
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
S
Security @ Cisco Blogs
H
Heimdal Security Blog
Hacker News: Ask HN
Hacker News: Ask HN
Help Net Security
Help Net Security
U
Unit 42
云风的 BLOG
云风的 BLOG
The Hacker News
The Hacker News
Cisco Talos Blog
Cisco Talos Blog
量子位
F
Full Disclosure
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 叶小钗
有赞技术团队
有赞技术团队
T
Troy Hunt's Blog
P
Privacy & Cybersecurity Law Blog
Forbes - Security
Forbes - Security
人人都是产品经理
人人都是产品经理
L
Lohrmann on Cybersecurity
Apple Machine Learning Research
Apple Machine Learning Research
Microsoft Security Blog
Microsoft Security Blog
博客园 - Franky
腾讯CDC
AI
AI
Last Week in AI
Last Week in AI
Latest news
Latest news
Google Online Security Blog
Google Online Security Blog
N
Netflix TechBlog - Medium
Engineering at Meta
Engineering at Meta
GbyAI
GbyAI
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
IT之家
IT之家
Martin Fowler
Martin Fowler
Blog — PlanetScale
Blog — PlanetScale
V2EX - 技术
V2EX - 技术
酷 壳 – CoolShell
酷 壳 – CoolShell

博客园 - 海乐学习

Java Maven 开发的常用命令 C语言开发的常用命令 三汇Linux配置Config说明 Java实现优雅的关闭程序并执行清理流程的写法 C语言开发中优雅的关闭程序并执行清理流程的写法 将C语言开发的程序做成 麒麟系统的服务(Systemd 标准服务,Linux 通用) 实现开机自启动 ZeroMQ的DEALER双帧结构(路由空帧 + 业务帧)(支持异步收发、主动推送事件)C写服务端 java写客户端 ZeroMQ中ZMQ_DEALER单帧数据(支持异步收发、主动推送事件)C写服务端 java写客户端 win10系统中 关闭专注助手 执行 xx.sh 脚本文件时出现: /bin/bash^M:解释器错误: 没有那个文件或目录 运行编译打包好的 xxx.jar 中没有主清单属性 出现这个错误 将Java编译的 .jar文件做成 麒麟系统的服务(Systemd 标准服务,Linux 通用) 实现开机自启动 将Java编译的 .jar文件做成windows服务 实现开机自启动 方法二 RabbitMQ在麒麟系统中离线安装说明 VMware启动虚似机后出现 无法获取快照信息: 锁定文件失败 模块“Snapshot”启动失败。未能启动虚拟机。 C语言在Linux中开发完整Demo包含读配置文件写日志和定时器Timer C语言在Linux中开发读取配置文件app.conf 麒麟V10 Server系统中搭建C语言开发环境 麒麟ServerV10 修改IP4地址 麒麟ServerV10 配置IP4 当系统中有两个版本的Maven时,用IDEA创建Maven有时会出错 麒麟ServerV10安装 espeak-ng 和 ffmpeg 方法 C语言在Linux中开发没有界面纯后台运行的Demo程序(含日志和Timer) C语言在Linux中开发使用定时器Timer在界面上显示时间 C语言在Linux中开发带界面的程序(含每小时日志) C语言在Linux中开发第一个项目Hello Word 在apache-maven项目中使用log4写日志 在apache-maven项目中解决中文乱码问题 在apache-maven项目中读取配置文件 创建apache-maven项目 远程桌面连接时出现身份验证错误 要求的函数不受支持 这可能是由于CredSSP加密数据库修正 win10系统查看电脑从锁屏状态回到使用状态 apache-maven的常用命令 C语言在 Linux 中的常用命令 apache-maven安装配置 麒麟CentOS下安装ZeroMQ开发包 Window上用VS Code + Remote-SSH组件的方式来实现开发编译Linux上的C++程序 win10弹出 无法使用内置管理员账户打开 Microsoft Edge。请使用其他账户登录 在麒麟系统上安装Qwen3-TTS文字转语音 在麒麟系统上安装MaryTTS文字转语音 FTP上传Linux/Unix文件系统权限的修改方法 麒麟系统Kylin Linux Advanced Server 中安装 python3.10 将exe做成windows服务 java实现TTS文字转语音wav (Jacob + SAPI) node.js和Next.js 编译部署说明
java实现ftp上传
海乐学习 · 2026-01-13 · via 博客园 - 海乐学习

java  maven 实现 ftp 上传

pom.xml

    <!-- Apache Commons Net 用于 FTP 操作 -->
    <dependency>
      <groupId>commons-net</groupId>
      <artifactId>commons-net</artifactId>
      <version>3.9.0</version>
    </dependency>

FtpUploader.java

package com.JoinCallCCVoxGuide;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
 

public class FtpUploader {
    protected static final Logger logger = LoggerFactory.getLogger(FtpUploader.class);

    private String server;
    private int port;
    private String username;
    private String password;
    private FTPClient ftpClient;

    /**
     * 构造函数
     * @param server FTP服务器地址
     * @param port FTP端口(默认21)
     * @param username 用户名
     * @param password 密码
     */
    public FtpUploader(String server, int port, String username, String password) {
        this.server = cleanServerAddress(server);  // 清理地址
        this.port = port;
        this.username = username;
        this.password = password;
        this.ftpClient = new FTPClient();
    }

    /**
     * 清理FTP服务器地址
     * 移除 ftp://, ftps:// 等协议前缀
     */
    private String cleanServerAddress(String server) {
        if (server == null || server.isEmpty()) {
            return server;
        }

        // 转换为小写,统一处理
        String cleaned = server.toLowerCase();

        // 移除协议前缀
        if (cleaned.startsWith("ftp://")) {
            cleaned = cleaned.substring(6);
        } else if (cleaned.startsWith("ftps://")) {
            cleaned = cleaned.substring(7);
        }

        // 如果还有端口号在地址中(如 ftp://192.168.1.150:21),需要分离
        // 但通常FTPClient的connect方法会单独处理端口
        // 这里只移除协议头,端口由另一个参数指定

        return cleaned.trim();
    }


    public FtpUploader(String server, String username, String password) {
        this(server, 21, username, password);
    }

    /**
     * 连接FTP服务器
     * @return 连接是否成功
     * @throws IOException
     */
    public boolean connect() throws IOException {
        ftpClient.connect(server, port);
        int replyCode = ftpClient.getReplyCode();

        if (!FTPReply.isPositiveCompletion(replyCode)) {
            ftpClient.disconnect();
            logger.error("FTP服务器拒绝连接,回复码: {}", replyCode);
            return false;
        }

        boolean loginSuccess = ftpClient.login(username, password);
        if (!loginSuccess) {
            logger.error("FTP登录失败,用户名或密码错误");
            return false;
        }

        // 设置被动模式(适合大多数防火墙)
        ftpClient.enterLocalPassiveMode();

        // 设置文件传输类型为二进制
        ftpClient.setFileType(FTP.BINARY_FILE_TYPE);

        logger.info("成功连接到FTP服务器: {}:{}", server, port);
        return true;
    }

    /**
     * 上传文件
     * @param localFilePath 本地文件路径
     * @param remoteFilePath 远程文件路径
     * @return 上传是否成功
     * @throws IOException
     */
    public boolean uploadFile(String localFilePath, String remoteFilePath) throws IOException {
        File localFile = new File(localFilePath);

        if (!localFile.exists()) {
            logger.error("本地文件不存在: {}", localFilePath);
            return false;
        }

        // 如果远程目录不存在,创建目录
        String remoteDir = getRemoteDirectory(remoteFilePath);
        if (remoteDir != null && !remoteDir.isEmpty()) {
            createRemoteDirectory(remoteDir);
        }

        try (InputStream inputStream = new FileInputStream(localFile)) {
            boolean success = ftpClient.storeFile(remoteFilePath, inputStream);
            if (success) {
                logger.info("文件上传成功: {} -> {}", localFilePath, remoteFilePath);
            } else {
                logger.error("文件上传失败: {}", localFilePath);
            }
            return success;
        }
    }

    /**
     * 上传整个目录
     * @param localDirPath 本地目录路径
     * @param remoteDirPath 远程目录路径
     * @return 上传是否成功
     * @throws IOException
     */
    public boolean uploadDirectory(String localDirPath, String remoteDirPath) throws IOException {
        File localDir = new File(localDirPath);

        if (!localDir.exists() || !localDir.isDirectory()) {
            logger.error("本地目录不存在或不是目录: {}", localDirPath);
            return false;
        }

        // 创建远程目录
        createRemoteDirectory(remoteDirPath);

        File[] files = localDir.listFiles();
        if (files == null) {
            return true;
        }

        boolean allSuccess = true;
        for (File file : files) {
            String remoteFilePath = remoteDirPath + "/" + file.getName();

            if (file.isDirectory()) {
                // 递归上传子目录
                allSuccess &= uploadDirectory(file.getAbsolutePath(), remoteFilePath);
            } else {
                // 上传文件
                allSuccess &= uploadFile(file.getAbsolutePath(), remoteFilePath);
            }
        }

        return allSuccess;
    }

    /**
     * 创建远程目录(支持多级目录创建)
     * @param remoteDirPath 远程目录路径
     * @return 创建是否成功
     * @throws IOException
     */
    private boolean createRemoteDirectory(String remoteDirPath) throws IOException {
        // 分隔符标准化
        remoteDirPath = remoteDirPath.replace("\\", "/");

        String[] directories = remoteDirPath.split("/");
        StringBuilder currentPath = new StringBuilder();

        for (String dir : directories) {
            if (dir.isEmpty()) continue;

            currentPath.append("/").append(dir);
            String path = currentPath.toString();

            // 检查目录是否存在,不存在则创建
            if (!ftpClient.changeWorkingDirectory(path)) {
                boolean success = ftpClient.makeDirectory(path);
                if (success) {
                    logger.debug("创建远程目录: {}", path);
                } else {
                    logger.error("创建远程目录失败: {}", path);
                    return false;
                }
            }
        }

        return true;
    }

    /**
     * 从文件路径中提取目录部分
     * @param filePath 文件路径
     * @return 目录路径
     */
    private String getRemoteDirectory(String filePath) {
        int lastSlash = filePath.lastIndexOf('/');
        if (lastSlash > 0) {
            return filePath.substring(0, lastSlash);
        }
        return "";
    }

    /**
     * 断开FTP连接
     */
    public void disconnect() {
        if (ftpClient.isConnected()) {
            try {
                ftpClient.logout();
                ftpClient.disconnect();
                logger.info("FTP连接已关闭");
            } catch (IOException e) {
                logger.error("关闭FTP连接时出错", e);
            }
        }
    }

    /**
     * 设置连接超时时间(毫秒)
     * @param timeout 超时时间
     */
    public void setTimeout(int timeout) {
        ftpClient.setConnectTimeout(timeout);
        ftpClient.setDefaultTimeout(timeout);
        ftpClient.setDataTimeout(timeout);
    }

    /**
     * 检查FTP服务器是否可连接
     * @return 是否可连接
     */
    public boolean isConnected() {
        return ftpClient.isConnected();
    }
}

App.java

package com.JoinCallCCVoxGuide;


/**
 * Hello world!
 */
public class App {
    protected static final Logger logger = LoggerFactory.getLogger(App.class);

    public static void main(String[] args) {
        //System.out.println("Hello World!");
 
        // 配置FTP连接参数
        String server = "ftp://192.168.1.150";
        int port =  21;
        String username = "support";
        String password =  "12345678";
        //远程路径
        String remoteFilePath =  "/ysapps/pbxcenter/var/lib/asterisk/sounds/record/NULL.wav";
        //本地文件
        String localFilePath = "d:\\JoinCallCCWav\\";

        localFilePath=localFilePath+"DHCD.wav";

        // 创建上传器实例
        FtpUploader uploader = new FtpUploader(server, port, username, password);

        try {
            // 1. 连接FTP服务器
            if (!uploader.connect()) {
                System.err.println("连接FTP服务器失败");
                return;
            }

            // 2. 设置超时时间(可选)
            uploader.setTimeout(30000);

            // 3. 上传单个文件
            boolean success = uploader.uploadFile(localFilePath, remoteFilePath);
            if (success) {
                System.out.println("文件上传成功");
            }

            // 4. 上传整个目录(可选)
            //String localDir = "/path/to/local/directory";
            //String remoteDir = "/upload/directory";
            //success = uploader.uploadDirectory(localDir, remoteDir);
            //if (success) {
            //    System.out.println("目录上传成功");
            //}

            // 5. 使用FTPS(安全FTP)示例
            //useFtpsExample();

        } catch (Exception e) {
            System.err.println("FTP操作出错: " + e.getMessage());
            e.printStackTrace();
        } finally {
            // 确保断开连接
            uploader.disconnect();
        }
    }
 


}