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获取文件更改偏移量 的相关文章

  • 如何使用javac编译java包结构

    我正在尝试编译 从命令行 一个 java 包 该包导入我自己的另一个包 我正在关注一个在线教程 http www roseindia net java master java createsubpackage shtml但当我尝试编译最终的
  • 在 catch 块中重新抛出异常是否有意义?

    从 catch 块中抛出异常只是为了记录消息以便我们确定导致异常的原因是否有意义 Code public void saveLogs Logs logs throws RemoteException try LogsOps saveLogs
  • 如何在 Java 中验证从 Azure AD B2C 生成的 JWT 令牌?

    我正在寻找 Java 代码示例来验证 Azure AD B2C 令牌 我们可以使用哪些依赖项 所有 JWT 令牌的 JWT 令牌验证步骤或代码是否相同还是会有所不同 我们的项目中没有使用 Spring Security 有大量的图书馆her
  • 从字符串中删除多个子字符串 - Java

    我需要从给定字符串中删除多个子字符串 例子 String exclude one two three String input if we add one and two we get three 我希望我的程序从输入字符串中删除所有出现的
  • JAVA_HOME环境变量和Java JDK趣事

    我想让 Java 在 1 6xxx 上运行 我更改了 JAVA HOME 变量并将其指向目录 C Program Files Java jdk1 6 0 16 我重新启动 PC 我想我可以检查我的机器指向哪个版本的 Java 但它仍然指向旧
  • 如何测试 Jersey REST Web 服务?

    我已经编写了一个 Restful Web 服务 并且必须使用 JUnit4 对其进行测试 我已经使用 Jersey Client 编写了一个客户端 但想知道我是否只能使用 junit4 测试我的服务 至少有人可以帮我提供样品吗 我的休息服务
  • Guice:当 FactoryBuilder 中提供合适的构造函数时,“找不到合适的构造函数”

    我使用 Guice 进行依赖注入 但收到此错误 1 Could not find a suitable constructor in java lang Void Classes must have either one and only
  • Java JNDI 名称 java:/

    我正在遵循教程 https docs oracle com javase tutorial jndi index html https docs oracle com javase tutorial jndi index html 我的冒险
  • 打印数组时出错

    我得到这个代码 import java util import java io public class Oblig3A public static void main String args OrdAnalyse O new OrdAna
  • 如何将 ArrayList 中的所有值相加或转换为 ArrayList

    我试图将 ArrayList 中的所有值相加 但没有任何方法可以让我得到总和 我必须找到从文本文件中提取的数字的平均值 public static void main String args throws IOException File
  • MongoDb Spring 在嵌套对象中查找

    我正在使用 Spring Data Mongodb 和这样的文档 id ObjectId 565c5ed433a140520cdedd7f attributes 565c5ed433a140520cdedd73 333563851 list
  • 如何使 JFileChooser 仅显示具有某些特定名称 Java 的文件夹

    有什么方法可以让 JFileChooser 加载时仅显示名称为 Hello 的文件夹 这是我的代码 它显示所有文件夹以及扩展名为 py 和 java 的文件 我想添加文件夹名称限制 FileNameExtensionFilter filte
  • 使用 Jboss7 加载资源返回 null

    如何使用Jboss7 1从java代码中加载图像等资源 这曾经与 Jboss4 一起使用 this getClass getClassLoader getResourceAsStream myapp includes images imag
  • Spring portlet mvc:@Valid 似乎不起作用

    我创建了一个 bean 类并在我的控制器中使用它 但它似乎不起作用 也就是说 即使我输入了无效的年龄 result hasErrors仍然是假的 豆类 public class User Min 13 private int age pri
  • 如何将 .txt 文件的最后 5 行读入 java

    我有一个包含多个条目的文本文件 例如 hello there my name is JoeBloggs 我如何按降序阅读最后五个条目 即来自 JoeBloggs 那里 我目前有代码只能读取最后一行 public class TestLast
  • 如何强制 Spark 执行代码?

    我如何强制 Spark 执行对 map 的调用 即使它认为由于其惰性求值而不需要执行它 我试过把cache 与地图调用 但这仍然没有解决问题 我的地图方法实际上将结果上传到 HDFS 所以 它并非无用 但 Spark 认为它是无用的 简短回
  • 如何为用户的活动设置计时器?

    如果用户在 5 小时内停止工作 我需要执行特定的方法 假设用户已登录 但他在 5 小时内没有向数据库的特定表添加任何记录 任何时候用户将记录添加到指定的表中 该特定用户的计时器都应该重置 否则它将继续运行 如果达到 5 小时 应用程序应显示
  • 如何在java中进行多处理,以及预期的速度提升是多少?

    我是一个新手 使用 Java 对 csv 文件进行一些数据处理 为此 我使用 Java 的多线程功能 线程池 将 csv 文件批量导入到 Java 中 并对每一行执行一些操作 在我的四核处理器上 多线程大大加快了处理速度 我很想知道多处理如
  • 无法取消 GWT 中的重复计时器

    我正在尝试在 GWT 中安排一个重复计时器 它将每一毫秒运行一次 轮询某个事件 如果发现满意 则执行某些操作并取消计时器 我尝试这样做 final Timer t new Timer public void run if condition
  • eclipse.ui.menus 的名称过滤器

    我有一个菜单贡献 通过实现org eclipse ui menus扩展点 我想仅为特定文件扩展名 例如 pld 提供此菜单贡献 但我不知道如何使用 visibleWhen 来做到这一点 有任何想法吗 更新 到目前为止我的扩展点

随机推荐

  • 为什么尝试使用 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