java通过FTP跨服务器动态监听读取指定目录下文件数据
背景:
1、文件数据在A服务器(windows)(不定期在指定目录下生成),项目应用部署在B服务器(Linux);
2、项目应用在B服务器,监听A服务器指定目录,有新生成文件,进行读取文件信息,持久化数据;
3、提供两块内容,第一安装windows FTP服务;第二项目源码,希望可以帮助到你。
共计4种方案,试错采用了第三种方案,第四种方案没有试。
1、使用jcsh.jar提供方法读取文件信息,但需要A服务器开通SSH远程连接,一般linux服务器都是默认开通的,可直接读取连接读取,windows系统需安装SSH,因现场环境A服务器是windows2003,故放弃这种方法。
2、曲线救国,通过脚本(脚本监听比较困难,故放弃)把A服务器信息定时存入B服务器(Linux),再通过jcsh.jar读取文件信息。
3、通过A服务器安装FTP服务,B服务器安装FTP客户端,使用java动态监听该目录下生成文件读取信息。
4、把A服务器指定目录进行共享(等同于共享的这个目录就是B服务的目录了),再进行读取,因第三种方案成功,故没有尝试第四种方案。
windows安装FTP服务
1、开启ftp服务:控制面板–程序和功能–启用或关闭windows功能–标红框全部打开–点击确定
2、新建站点:
控制面板–大图标–管理工具
IIS管理器
网站–添加FTP站点
以上就是windows安装FTP服务的过程,我这演示了匿名创建站点,谁都可以访问,还可以新建用户,需要用户登录才能访问。
源码
引入该依赖
<dependency><groupId>commons-net</groupId><artifactId>commons-net</artifactId><version>3.6</version>
</dependency>
FileChangeData
@Data
public class FileChangeData {/*** 文件信息* */private FTPFile ftpFile;/*** 文件改变类型* */private FileChangeType eventType;/*** 文件名称* */private String fileName;/*** 文件大小* */private Long fileSize;/*** FTPClient* */private FTPClient ftpClient;/*** 获取文件输入流* @return InputStream* */public InputStream getInputStream(String filePathName) {//如果是删除事件则不能够获取流if (Objects.equals(eventType, FileChangeType.FILE_DELETED)) {return null;}try {return ftpClient.retrieveFileStream(filePathName);} catch (IOException e) {return null;}}
}
FileChangeEvent
public interface FileChangeEvent {/*** 文件发生改变时触发此方法* @param fileChangeData 文件发生了改变* */@Functionvoid change(FileChangeData fileChangeData) throws IOException;
}
FTPService
public interface FTPService {/*** ftp登陆* @return boolean 是否登陆成功* */FTPClient login();/*** ftp登出* @return boolean 是否登出成功* */boolean loginOut();/*** 获取文件列表* @return FTPFile[] 文件列表* */FTPFile[] listFile();/*** 监听文件夹的改变* @param fileChangeEvent 文件改变事件* */void addListenerFileChange(FileChangeEvent fileChangeEvent);
}
ListenerChangeRunnable
public interface ListenerChangeRunnable extends Runnable {/*** 停止监听文件* @return boolean 是否停止成功* */boolean stopListener();
}
FTPServiceImpl
@Service
public class FTPServiceImpl implements FTPService {@Autowiredprivate FTPConfig ftpConfig;private String SPLIT = ":";private ThreadLocal<FTPClient> currentFTPClient;private ThreadLocal<ListenerChangeRunnable> currentListener;public FTPServiceImpl() {this.currentFTPClient = new ThreadLocal<>();this.currentListener = new ThreadLocal<>();}@Overridepublic FTPClient login() {FTPClient ftpClient = new FTPClient();try {ftpClient.connect(ftpConfig.getFtpIp(), ftpConfig.getFtpPort());ftpClient.login(ftpConfig.getUsername(), ftpConfig.getPassword());
// ftpClient.setControlEncoding("gb2312");this.currentFTPClient.set(ftpClient);return ftpClient;} catch (Exception e) {return null;}}@Overridepublic boolean loginOut() {try {currentFTPClient.get().logout();currentFTPClient.get().disconnect();return Boolean.TRUE;} catch (Exception e) {return Boolean.FALSE;}}@Overridepublic FTPFile[] listFile() {FTPClient ftpClient = this.currentFTPClient.get();try {return ftpClient.listFiles();} catch (Exception e) {return null;}}@Overridepublic void addListenerFileChange(FileChangeEvent fileChangeEvent) {FTPClient ftpClient = this.currentFTPClient.get();ListenerFileChangeThreadRunnable listenerFileChangeThread = new ListenerFileChangeThreadRunnable(ftpClient, fileChangeEvent);this.currentListener.set(listenerFileChangeThread);new Thread(listenerFileChangeThread).start();}
}
ListenerFileChangeThreadRunnable
@Slf4j
public class ListenerFileChangeThreadRunnable implements ListenerChangeRunnable {private final FTPClient ftpClient;private volatile boolean stop;private final Map<String, Long> fileMemory;private final FileChangeEvent fileChangeEvent;public ListenerFileChangeThreadRunnable(FTPClient ftpClient, FileChangeEvent fileChangeEvent) {this.ftpClient = ftpClient;this.fileChangeEvent = fileChangeEvent;this.fileMemory = new HashMap<>();}@Overridepublic void run() {while (!stop) {try {FTPFile[] ftpFiles = ftpClient.listFiles();//判断文件被删除if (fileMemory.size() > 0) {Set<String> fileNames = new HashSet<>();for (FTPFile ftpFile : ftpFiles) {if (ftpFile.isDirectory()) {log.info("文件夹不做删除判断");continue;}fileNames.add(ftpFile.getName());}Set<Map.Entry<String, Long>> entries = fileMemory.entrySet();for (Map.Entry<String, Long> map : entries) {if (!fileNames.contains(map.getKey())) {log.info("文件{}被删除了", map.getKey());FileChangeData fileChangeData = new FileChangeData();fileChangeData.setEventType(FileChangeType.FILE_DELETED);fileChangeData.setFileName(map.getKey());fileChangeData.setFileSize(map.getValue());fileMemory.remove(map.getKey());entries.remove(map.getKey());fileChangeEvent.change(fileChangeData);}}}//判断文件是否有更改或新增for (FTPFile ftpFile: ftpFiles) {//判断是否为文件夹if (ftpFile.isDirectory()) {
// log.info("{}为文件不进行监听操作", ftpFile.getName());continue;}FileChangeData fileChangeData = new FileChangeData();fileChangeData.setFileName(ftpFile.getName());
// fileChangeData.setFileName("D:\\ftptest\\aaa\\"+ftpFile.getName());fileChangeData.setFileSize(ftpFile.getSize());fileChangeData.setFtpFile(ftpFile);//文件是否存在于缓存文件列表中if (fileMemory.containsKey(ftpFile.getName())) {
// log.info("文件{}在内存中已经存在,进行大小判断", ftpFile.getName());if (!Objects.equals(fileMemory.get(ftpFile.getName()), ftpFile.getSize())) {
// log.info("文件{}在内存中已经存在且大小不一致,进行更新缓存操作", ftpFile.getName());fileMemory.put(ftpFile.getName(), ftpFile.getSize());fileChangeData.setEventType(FileChangeType.FILE_UPDATE);fileChangeEvent.change(fileChangeData);}continue;}
// log.info("文件{}在内存中不存在进行缓存操作", ftpFile.getName());fileMemory.put(ftpFile.getName(), ftpFile.getSize());fileChangeData.setEventType(FileChangeType.FILE_ADD);fileChangeEvent.change(fileChangeData);}} catch (Exception e) {continue;//throw new RuntimeException(e);}try {TimeUnit.SECONDS.sleep(20);} catch (InterruptedException e) {continue;//throw new RuntimeException(e);}}}@Overridepublic boolean stopListener() {this.stop = Boolean.TRUE;this.fileMemory.clear();return this.stop;}
}
FileChangeType
public enum FileChangeType {FILE_UPDATE(0, "文件更新"),FILE_ADD(1, "文件添加"),FILE_DELETED(2, "文件删除");@Getterprivate Integer type;@Getterprivate String desc;FileChangeType(Integer type, String desc) {this.type = type;this.desc = desc;}
}
FTPConfig
@Data
@Configuration
public class FTPConfig {@Value("${ftp.ip:ftp的ip}")private String ftpIp;@Value("${ftp.port:ftp端口,默认21}")private Integer ftpPort;@Value("${ftp.username:ftp创建的用户名}")private String username;@Value("${ftp.password:ftp创建的用户名密码}")private String password;
}
SendEmailApplicationTests
@Component
class SendEmailApplicationTests implements ApplicationRunner {@Autowiredprivate FTPService ftpService;void ftpTest() {FTPClient ftpClient = ftpService.login();ftpService.addListenerFileChange(ftpFile -> {System.out.println(String.format("文件%s被改变了,文件改变类型%s", ftpFile.getFileName(), ftpFile.getEventType().getDesc()));InputStream inputStream = ftpClient.retrieveFileStream("/"+ ftpFile.getFileName());if(inputStream!=null){BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream,"GBK"));String s = null;List<String> listStr = new ArrayList<>();//读取的数据在listStrwhile ((s = reader.readLine()) != null) {System.out.println("===================>" + s);listStr.add(s);}//处理业务逻辑inputStream.close();reader.close();ftpClient.completePendingCommand();}});}@Overridepublic void run(ApplicationArguments args) throws Exception {ftpTest();}
}
相关文章:

java通过FTP跨服务器动态监听读取指定目录下文件数据
背景: 1、文件数据在A服务器(windows)(不定期在指定目录下生成),项目应用部署在B服务器(Linux); 2、项目应用在B服务器,监听A服务器指定目录,有新…...

5G边缘计算网关的功能及作用
5G边缘计算网关具有多种功能。 首先,它支持智能云端控制,可以通过5G/4G/WIFI等无线网络将采集的数据直接上云,实现异地远程监测控制、预警通知、报告推送和设备连接等工作。 其次,5G边缘计算网关可以采集各种数据,包…...

阿里云AIGC小说生成【必得京东卡】
任务步骤 此文真实可靠不做虚假宣传,绝对真实,可截图为证。 领取任务 链接(复制到wx打开):#小程序://ITKOL/1jw4TX4ZEhykWJd 教程实践 打开函数计算控制台 应用->创建应用->人工智能->通义千问 AI 助手-…...

数据结构之AVL树
map/multimap/set/multiset这几个容器有个共同点是: 其底层都是按照二叉搜索树来实现的,但是普通的二叉搜索树有其自身的缺陷, 假如往树中插入的元素有序或者接近有序, 二叉搜索树就会退化成单支树, 时间复杂度会退化成O(N),因此map、set等关联式容器的底层结构是对二叉树进行了…...

如何用Java实现一个基于机器学习的情感分析系统,用于分析文本中的情感倾向
背景:练习两年半(其实是两周半),利用工作闲余时间入门一下机器学习,本文没有完整的可实施的案例,由于知识体系不全面,目前代码只能运行,不能准确的预测 卡点: 1 由于过…...
开发聚合支付的的意义
开发聚合支付的意义在于整合各种支付方式,为消费者和商家提供便捷高效的支付体验,同时满足商家的多元化支付需求,提高支付效率和用户体验。 具体来说,聚合支付具有以下意义: 方便快捷:聚合支付整合了多种…...

ChatGPT生产力|中科院学术ChatGPT优化配置
资源链接:GitHub - binary-husky/gpt_academic b站配置讲解链接:chatgpt-academic 新手运行官方精简指南(科研chatgpt拓展) 某知配置图文讲解:图文详解:在windows中部署ChatGPT学术版 - 知乎 (zhihu.com) 一…...
语音播报speechSynthesis最简单的例子(亲测有用)
最简单的例子,在chrome上亲测有效: const utterThis new SpeechSynthesisUtterance(我来试试呀); const synth window.speechSynthesis; synth.speak(utterThis);加入配置,可以配置语言、音量、语速、音高,继续玩: …...
呆头鹅-全自动视频混剪,批量剪辑批量剪视频,探店带货系统,精细化顺序混剪,故事影视解说,视频处理大全,精细化顺序混剪,多场景裂变,多视频混剪
视频闪闪-全自动视频混剪,探店带货系统,多视频混剪,让你成为视频处理大师! 一、全自动视频混剪 www.shipinshanshan.com 你是否曾经厌烦于冗长的视频剪辑过程?是否曾经为了一个短短的混剪视频而熬夜加班?现…...
牛客竞赛网(爱吃素)
题目描述 牛妹是一个爱吃素的小女孩,所以很多素数都害怕被她吃掉。 一天,两个数字aaa和bbb为了防止被吃掉,决定和彼此相乘在一起,这样被吃掉的风险就会大大降低,但仍有一定的可能被吃掉,请你判断他们相乘后…...
基于高效多分支卷积神经网络的生长点精确检测与生态友好型除草
Eco-friendly weeding through precise detection ofgrowing points via efficient multi-branch convolutional neural networks 摘要1、介绍2、相关工作2.1 杂草检测,高效除草2.2 用于密集预测任务的编解码网络2.3 语义图形是一种有效的标签方法3、总结摘要 在本研究中,我…...
11月9日,每日信息差
今天是2023年11月09日,以下是为您准备的17条信息差 第一、中国电信在进博会上与诺基亚、爱立信、英特尔、戴尔、三星达成采购合作意向。采购范围涵盖无线、数据和传输、固网终端、服务器、CPU、手机终端等设备及服务 第二、马斯克称SpaceX明年将每两天发射一次火箭…...

什么是 eCPM?它与 CPM 有何不同?
目录 eCPM 什么是 eCPM?它与 CPM 有何不同? 如何计算 eCPM? 该指标的主要优势有哪些? eCPM 底价 eCPM 达到多少比较合适? eCPM 每千人有效成本 (eCPM) 是指发行商(App 开发者)在 App 中每…...

Power Automate-创建和运行
网站:Microsoft Power Automate 根据自己需求选择创建 选择需要的触发方式,以即时云端流为例,点击触发流 点击添加新步骤 可以选择多种微软应用或者自定义应用连接 此处以向SharePoint列表追加项为例,要提前创建好SharePoint列表…...

【STM32 开发】| INA219采集电压、电流值
目录 前言1 原理图2 IIC地址说明3 寄存器地址说明4 开始工作前配置5 程序代码1)驱动程序2)头文件3) 测试代码 前言 INA219 是一款具备 I2C 或 SMBUS 兼容接口的分流器和功率监测计。该器件监测分流器电压降和总线电源电压,转换次数和滤波选项…...

蓝桥杯每日一题203.11.7
题目描述 题目分析 使用dp思维,当前位置是否可行是有上一位置推来,计算出最大的可行位置即可 #include <stdio.h> #include <string.h>#define N 256 int f(const char* s1, const char* s2) {int a[N][N];int len1 strlen(s1);int len2 …...

ESP32建立TCP连接
ESP32建立TCP连接 1.搭建ESP-IDF开发环境 搭建开发环境直接从官网下载即可。 https://docs.espressif.com/projects/esp-idf/zh_CN/v5.1.1/esp32s3/index.html https://dl.espressif.com/dl/esp-idf/?idf4.4 使用官方的下载器下载好,就可以自动安装࿰…...
普华永道成功举办《国有基金高质量发展提效创效服务》主题分享活动,助力国有基金提效创效
上海,2023年11月10日 —今天普华永道在上海中国国际进口博览会(以下简称“进博会”)现场举办《为“国”出力,“普”实有“华”—— 普华永道国有基金高质量发展提效创效服务》主题分享活动,就国有基金监督、管理、投资…...

黑洞路由的几种应用场景
第一种在内网中产生环路: 这种核心交换机上肯定写一条默认路由 0.0.0.0 0 10.0.0.1 出口路由要写一条192.168.0.0 16 10.0.0.2 如果出口路由访问一条不存在的内网网段,又或者访问的那台终端停机了,那就会产生三层环路,数据包在…...
数据分析:智能企业七步曲(一)
原创: MicroStrategy微策略中国 作者:数据杰论 时间走到2018年最后一个季度,过去几年热炒的大数据概念正在各行各业开始落地并展开实际应用,核心是关注数据如何能为企业带来价值。因此,数据分析及其种种实现手段不断被…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...

关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...

CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...

srs linux
下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935,SRS管理页面端口是8080,可…...

Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...