Java 7 watchservice获取文件更改偏移量

2024-05-11

我刚刚尝试使用 Java 7 WatchService 来监视文件的更改。

这是我敲出的一些代码:

WatchService watcher = FileSystems.getDefault().newWatchService();

    Path path = Paths.get("c:\\testing");

    path.register(watcher, StandardWatchEventKinds.ENTRY_MODIFY);

    while (true) {
        WatchKey key = watcher.take();

        for (WatchEvent event : key.pollEvents()) {
            System.out.println(event.kind() + ":" + event.context());
        }

        boolean valid = key.reset();
        if (!valid) {
            break;
        }
    }

这似乎有效,并且我收到有关文件“changethis.txt”修改时的通知。

但是,除了能够在文件更改时发出通知之外,是否还可以通知文件中发生修改的位置?

我浏览了 Java 文档,但似乎找不到任何东西。

使用 WatchService 可以实现这一点吗?还是必须实现一些自定义功能?

Thanks


不管怎样,我已经破解了一些概念证明,它能够

  • 检测监视目录中添加、修改和删除的文件,
  • 显示每个更改的统一差异(以及添加/删除文件时的完整差异),
  • 通过保留源目录的卷影副本来跟踪连续的更改,
  • 以用户定义的节奏(默认为 5 秒)工作,以免在短时间内打印太多小的差异,而是偶尔打印较大的差异。

有几个限制可能会成为生产环境中的障碍:

  • 为了不使示例代码变得不必要的复杂化,在创建影子目录时一开始就复制了子目录(因为我已经回收了现有的方法来创建深层目录副本),但在运行时忽略了子目录。仅监视监视目录正下方的文件,以避免递归。
  • 不满足您不使用外部库的要求,因为我真的想避免重新发明轮子来创建统一的差异。
  • 该解决方案的最大优点 - 它能够检测文本文件中任何位置的更改,而不仅仅是在文件末尾(例如tail -f- 这也是它最大的缺点:每当文件发生更改时,都必须对其进行完全卷影复制,否则程序无法检测到后续更改。因此,对于非常大的文件,我不推荐使用此解决方案。

如何构建:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>de.scrum-master.tools</groupId>
    <artifactId>SO_WatchServiceChangeLocationInFile</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>com.googlecode.java-diff-utils</groupId>
            <artifactId>diffutils</artifactId>
            <version>1.3.0</version>
        </dependency>
    </dependencies>
</project>

源代码(抱歉,有点长):

package de.scrum_master.app;

import difflib.DiffUtils;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.LinkedList;
import java.util.List;

import static java.nio.file.StandardWatchEventKinds.*;

public class FileChangeWatcher {
    public static final String DEFAULT_WATCH_DIR = "watch-dir";
    public static final String DEFAULT_SHADOW_DIR = "shadow-dir";
    public static final int DEFAULT_WATCH_INTERVAL = 5;

    private Path watchDir;
    private Path shadowDir;
    private int watchInterval;
    private WatchService watchService;

    public FileChangeWatcher(Path watchDir, Path shadowDir, int watchInterval) throws IOException {
        this.watchDir = watchDir;
        this.shadowDir = shadowDir;
        this.watchInterval = watchInterval;
        watchService = FileSystems.getDefault().newWatchService();
    }

    public void run() throws InterruptedException, IOException {
        prepareShadowDir();
        watchDir.register(watchService, ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE);
        while (true) {
            WatchKey watchKey = watchService.take();
            for (WatchEvent<?> event : watchKey.pollEvents()) {
                Path oldFile = shadowDir.resolve((Path) event.context());
                Path newFile = watchDir.resolve((Path) event.context());
                List<String> oldContent;
                List<String> newContent;
                WatchEvent.Kind<?> eventType = event.kind();
                if (!(Files.isDirectory(newFile) || Files.isDirectory(oldFile))) {
                    if (eventType == ENTRY_CREATE) {
                        if (!Files.isDirectory(newFile))
                            Files.createFile(oldFile);
                    } else if (eventType == ENTRY_MODIFY) {
                        Thread.sleep(200);
                        oldContent = fileToLines(oldFile);
                        newContent = fileToLines(newFile);
                        printUnifiedDiff(newFile, oldFile, oldContent, newContent);
                        try {
                            Files.copy(newFile, oldFile, StandardCopyOption.REPLACE_EXISTING);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    } else if (eventType == ENTRY_DELETE) {
                        try {
                            oldContent = fileToLines(oldFile);
                            newContent = new LinkedList<>();
                            printUnifiedDiff(newFile, oldFile, oldContent, newContent);
                            Files.deleteIfExists(oldFile);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
            watchKey.reset();
            Thread.sleep(1000 * watchInterval);
        }
    }

    private void prepareShadowDir() throws IOException {
        recursiveDeleteDir(shadowDir);
        Runtime.getRuntime().addShutdownHook(
            new Thread() {
                @Override
                public void run() {
                    try {
                        System.out.println("Cleaning up shadow directory " + shadowDir);
                        recursiveDeleteDir(shadowDir);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        );
        recursiveCopyDir(watchDir, shadowDir);
    }

    public static void recursiveDeleteDir(Path directory) throws IOException {
        if (!directory.toFile().exists())
            return;
        Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                Files.delete(file);
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                Files.delete(dir);
                return FileVisitResult.CONTINUE;
            }
        });
    }

    public static void recursiveCopyDir(final Path sourceDir, final Path targetDir) throws IOException {
        Files.walkFileTree(sourceDir, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                Files.copy(file, Paths.get(file.toString().replace(sourceDir.toString(), targetDir.toString())));
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                Files.createDirectories(Paths.get(dir.toString().replace(sourceDir.toString(), targetDir.toString())));
                return FileVisitResult.CONTINUE;
            }
        });
    }

    private static List<String> fileToLines(Path path) throws IOException {
        List<String> lines = new LinkedList<>();
        String line;
        try (BufferedReader reader = new BufferedReader(new FileReader(path.toFile()))) {
            while ((line = reader.readLine()) != null)
                lines.add(line);
        }
        catch (Exception e) {}
        return lines;
    }

    private static void printUnifiedDiff(Path oldPath, Path newPath, List<String> oldContent, List<String> newContent) {
        List<String> diffLines = DiffUtils.generateUnifiedDiff(
            newPath.toString(),
            oldPath.toString(),
            oldContent,
            DiffUtils.diff(oldContent, newContent),
            3
        );
        System.out.println();
        for (String diffLine : diffLines)
            System.out.println(diffLine);
    }

    public static void main(String[] args) throws IOException, InterruptedException {
        String watchDirName = args.length > 0 ? args[0] : DEFAULT_WATCH_DIR;
        String shadowDirName = args.length > 1 ? args[1] : DEFAULT_SHADOW_DIR;
        int watchInterval = args.length > 2 ? Integer.getInteger(args[2]) : DEFAULT_WATCH_INTERVAL;
        new FileChangeWatcher(Paths.get(watchDirName), Paths.get(shadowDirName), watchInterval).run();
    }
}

我建议使用默认设置(例如,使用名为“watch-dir”的源目录)并使用它一段时间,在编辑器中创建和编辑一些文本文件时观察控制台输出。它有助于理解软件的内部机制。如果出现问题,例如在 5 秒的节奏内创建一个文件,但又很快被删除,没有任何内容可以复制或比较,因此程序只会打印堆栈跟踪System.err.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java 7 watchservice获取文件更改偏移量 的相关文章

  • Java 中等效的并行扩展

    我在 Net 开发中使用并行扩展有一些经验 但我正在考虑在 Java 中做一些工作 这些工作将受益于易于使用的并行库 JVM 是否提供任何与并行扩展类似的工具 您应该熟悉java util concurrent http java sun
  • Java new Date() 打印

    刚刚学习 Java 我知道这可能听起来很愚蠢 但我不得不问 System out print new Date 我知道参数中的任何内容都会转换为字符串 最终值是 new Date 返回对 Date 对象的引用 那么它是如何打印这个的呢 Mo
  • 给定两个 SSH2 密钥,我如何检查它们是否属于 Java 中的同一密钥对?

    我正在尝试找到一种方法来验证两个 SSH2 密钥 一个私有密钥和一个公共密钥 是否属于同一密钥对 我用过JSch http www jcraft com jsch 用于加载和解析私钥 更新 可以显示如何从私钥 SSH2 RSA 重新生成公钥
  • Android:捕获的图像未显示在图库中(媒体扫描仪意图不起作用)

    我遇到以下问题 我正在开发一个应用程序 用户可以在其中拍照 附加到帖子中 并将图片保存到外部存储中 我希望这张照片也显示在图片库中 并且我正在使用媒体扫描仪意图 但它似乎不起作用 我在编写代码时遵循官方的Android开发人员指南 所以我不
  • 多个 Maven 配置文件激活多个 Spring 配置文件

    我想在 Maven 中构建一个环境 在其中我想根据哪些 Maven 配置文件处于活动状态来累积激活多个 spring 配置文件 目前我的 pom xml 的相关部分如下所示
  • 控制Android的前置LED灯

    我试图在用户按下某个按钮时在前面的 LED 上实现 1 秒红色闪烁 但我很难找到有关如何访问和使用前置 LED 的文档 教程甚至代码示例 我的意思是位于 自拍 相机和触摸屏附近的 LED 我已经看到了使用手电筒和相机类 已弃用 的示例 但我
  • Java按日期升序对列表对象进行排序[重复]

    这个问题在这里已经有答案了 我想按一个参数对对象列表进行排序 其日期格式为 YYYY MM DD HH mm 按升序排列 我找不到正确的解决方案 在 python 中使用 lambda 很容易对其进行排序 但在 Java 中我遇到了问题 f
  • Java TestNG 与跨多个测试的数据驱动测试

    我正在电子商务平台中测试一系列商店 每个商店都有一系列属性 我正在考虑对其进行自动化测试 是否有可能有一个数据提供者在整个测试套件中提供数据 而不仅仅是 TestNG 中的测试 我尝试不使用 testNG xml 文件作为机制 因为这些属性
  • 如何将 pfx 文件转换为 jks,然后通过使用 wsdl 生成的类来使用它来签署传出的肥皂请求

    我正在寻找一个代码示例 该示例演示如何使用 PFX 证书通过 SSL 访问安全 Web 服务 我有证书及其密码 我首先使用下面提到的命令创建一个 KeyStore 实例 keytool importkeystore destkeystore
  • 为什么HashMap不能保证map的顺序随着时间的推移保持不变

    我在这里阅读有关 Hashmap 和 Hashtable 之间的区别 http javarevisited blogspot sg 2010 10 difference Between hashmap and html http javar
  • JRE 系统库 [WebSphere v6.1 JRE](未绑定)

    将项目导入 Eclipse 后 我的构建路径中出现以下错误 JRE System Library WebSphere v6 1 JRE unbound 谁知道怎么修它 右键单击项目 特性 gt Java 构建路径 gt 图书馆 gt JRE
  • 如何从终端运行处理应用程序

    我目前正在使用加工 http processing org对于一个小项目 但是我不喜欢它附带的文本编辑器 我使用 vim 编写所有代码 我找到了 pde 文件的位置 并且我一直在从 vim 中编辑它们 然后重新打开它们并运行它们 重新加载脚
  • 如何从泛型类调用静态方法?

    我有一个包含静态创建方法的类 public class TestClass public static
  • 声明的包“”与预期的包不匹配

    我可以编译并运行我的代码 但 VSCode 中始终显示错误 早些时候有一个弹出窗口 我不记得是什么了 我点击了 全局应用 从那以后一直是这样 Output is there but so is the error The declared
  • simpleframework,将空元素反序列化为空字符串而不是 null

    我使用简单框架 http simple sourceforge net http simple sourceforge net 在一个项目中满足我的序列化 反序列化需求 但在处理空 空字符串值时它不能按预期工作 好吧 至少不是我所期望的 如
  • 获取 JVM 上所有引导类的列表?

    有一种方法叫做findBootstrapClass对于一个类加载器 如果它是引导的 则返回一个类 有没有办法找到类已经加载了 您可以尝试首先通过例如获取引导类加载器呼叫 ClassLoader bootstrapLoader ClassLo
  • 静态变量的线程安全

    class ABC implements Runnable private static int a private static int b public void run 我有一个如上所述的 Java 类 我有这个类的多个线程 在里面r
  • 捕获的图像分辨率太大

    我在做什么 我允许用户捕获图像 将其存储到 SD 卡中并上传到服务器 但捕获图像的分辨率为宽度 4608 像素和高度 2592 像素 现在我想要什么 如何在不影响质量的情况下获得小分辨率图像 例如我可以获取或设置捕获的图像分辨率为原始图像分
  • 使用 JMF 创建 RTP 流时出现问题

    我正处于一个项目的早期阶段 需要使用 RTP 广播DataStream创建自MediaLocation 我正在遵循一些示例代码 该代码目前在rptManager initalize localAddress 出现错误 无法打开本地数据端口
  • 使用 xpath 和 vtd-xml 以字符串形式获取元素的子节点和文本

    这是我的 XML 的一部分

随机推荐

  • 为什么尝试使用 Hamcrest 的 hasItems 的代码无法编译?

    为什么这个不能编译 哦 怎么办 import static org junit Assert assertThat import static org junit matchers JUnitMatchers hasItems ArrayL
  • Excel如何获取一个时间间隔内的小时数?

    我有两列 Night shift start 19 00 Night end 04 00 我每天都有一些日期列 Work started 07 30 Worked ended 22 00 我想获取夜班开始和夜班结束之间的小数小时数 我需要计
  • 用Java将图像添加到数据库

    我正在尝试将图像添加到 mysql 数据库中的 BLOB 字段 图像大小将小于 100kb 但是我遇到了问题 想知道将这些数据添加到数据库的更好方法是什么 com mysql jdbc MysqlDataTruncation 数据截断 第
  • 使用 BeautifulSoup 抓取评论标签内的表格

    我正在尝试使用 BeautifulSoup 从以下网页中抓取表格 https www pro football reference com boxscores 201702050atl htm https www pro football
  • 将应用程序级别用户名/用户 ID 注入 nginx/Apache 日志

    有没有办法将应用程序级别的用户名或 id 在本例中为 django 用户名或 id 注入 Apache 或 ngnix 日志中 请注意 我不是询问 HTTP 身份验证用户名 我目前正在使用一个简短的自定义中间件将此数据添加到响应标头 如下所
  • MetadataException:无法加载指定的元数据资源

    突然间我不断收到MetadataException在实例化我生成的ObjectContext班级 App Config 中的连接字符串看起来正确 自上次工作以来没有更改 我尝试从底层数据库重新生成一个新模型 edmx 文件 没有任何更改 有
  • 比较 PHP 中的 unix 时间戳 [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 在 PHP 中我有 diff abs
  • 我可以为 Android Activity 分配“默认”OnClickListener() 吗?

    我有一个 Activity 对于布局中的每个小部件 我调用 setOnClickListener 来分配我的 OnClick 处理程序 在我的 OnClick 处理程序中 我使用 switch 语句根据 View 参数的 ID 为每个按钮执
  • 在java中切换imageIcon?

    我有很多在窗口中移动的平面 线程 我想根据平面的方向切换 ImageIcon 例如 如果飞机向右飞行 则飞机的 imageIcon 是向右的 然后飞机向左飞行 则将 imageIcon 交换为飞机向左 我怎样才能在方法paintCompon
  • 媒体文件不在 cpanel 上的 django 应用程序中提供

    我有一个 django 应用程序在 cpanel 上运行 我不确定是否是我的问题 django 应用程序或 cpanel 服务器 当设置调试模式时True 我可以看到所有媒体文件 例如个人资料图片或pdf文件等 但是当设置调试模式时Fals
  • 定义自定义 Mupad 程序的一般相对搜索路径

    假设我有一个 mupad 笔记本myMupadNotebook mn在路径上 C projectFolder ABC abc 它调用程序MyMupadProcedure mu它位于 C DEF GHI 现在我有一个 Matlab 脚本mai
  • 软件音频线路输入

    这可能是也可能不是询问的地方 如果不是 就直接扔掉它 我有一个正在输出音频的软件 我想将其路由到另一个软件 简单的解决方案是将耳机插孔连接到麦克风插孔或在计算机上启用立体声混音 但是 我想要做的进一步实现将在一台机器上发生 2 个这样的实例
  • 三层 Asp.Net 应用程序中的异常处理

    1 据我了解 在three tierAsp Net应用程序我们应该通过以下方式实现异常处理 a 我们应该把try catch围绕代码块 位于三层中的任何一层 我们希望页面能够从该代码块正常恢复 当此代码生成异常时 b 我们不应该放try c
  • 在 Oracle 中创建数据库链接时出错

    我有两个数据库 需要编写跨数据库查询 所以我试图创建一个数据库链接 CREATE PUBLIC DATABASE LINK DBLink CONNECT TO SchemaName IDENTIFIED BY 123 using DBNam
  • 在 Java/Android 中检查字符串是否包含 URL 的最佳方法是什么?

    在 Java Android 中检查字符串是否包含 URL 的最佳方法是什么 最好的方法是检查字符串是否包含 com net org info 其他 或者有更好的方法吗 url 输入到 Android 中的 EditText 中 它可以是粘
  • 在 C++11 中,返回指向 std::string 中某个位置的引用/指针的最高效方法是什么?

    我正在构建一个使用的文本解析器std string作为字符串的核心存储 我知道这不是最佳的 编译器内的解析器为此使用优化的方法 在我的项目中 我不介意损失一些性能来换取更清晰和更容易的维护 一开始 我将大量文本读入内存 然后扫描每个字符以构
  • 动态/条件 SQL 连接?

    我在 MSSQL 表 TableB 中有数据 其中 dbo tableB myColumn 在特定日期后更改格式 我正在做一个简单的连接到该表 Select dbo tableB theColumnINeed from dbo tableA
  • 在 iPhone 中使用 Soap Web 服务与 wsdl2objc?

    我确实意识到这是一个重复的问题 但是唯一的其他问题已经很老了 所以我想知道是否有人最近有过使用最新版本的经验wsdl2objc http code google com p wsdl2objc 我正在编写一个应用程序 该应用程序将与第三方应
  • 图像识别后如何在vuforia sdk ImageTarget中显示布局而不是茶壶模型

    如果图像在 qualcomm vuforia sdk 中被识别 我们如何在布局中显示简单的文本 即 Hello 我正在使用 ImageTarget 的 qualcomm vuforia sdk 示例 现在它在识别图像后显示一个茶壶 我是增强
  • Java 7 watchservice获取文件更改偏移量

    我刚刚尝试使用 Java 7 WatchService 来监视文件的更改 这是我敲出的一些代码 WatchService watcher FileSystems getDefault newWatchService Path path Pa