【问题标题】:Detect changed files in a directory (java 8) from digest or checksum从摘要或校验和中检测目录(java 8)中更改的文件
【发布时间】:2019-11-06 23:36:05
【问题描述】:

我正在寻找一种简单的方法来检测重新启动之间目录中的文件是否已更改,以避免不必要的同步。在 java 8 库中执行此操作的最简单方法是什么?我应该对每个文件的 md5 摘要进行异或,还是对每个文件的校验和进行异或?

我们不需要处理进入子目录的 ATM。

此外,我们不应该使用操作系统事件来检测此更改,因为检测方法只会在启动时调用。目录中的文件数量可以在不同版本的应用程序之间改变,但这些文件通常不会在重新启动之间改变。

这看起来像是一篇相关的帖子: https://crypto.stackexchange.com/questions/1368/is-it-a-good-idea-to-use-bitwise-xor-on-a-set-of-md5-sums

【问题讨论】:

  • @LyjuIEdwinson 谢谢,但我特别不希望通过操作系统事件检测文件更改,因为此例程只会在系统启动时触发。
  • “避免不必要的同步”究竟是什么意思?您是否将文件镜像到另一个目录?那么也许你最好只使用 rsync 而不是自己滚动。
  • @Axel 特定于我们的应用程序,当这些文件被修改时,我们需要将控制器重新同步到我们的数据库,这个过程需要一段时间。基本上有一个大文件正在通过 xinclude 语句重构为较小的 xml 文件,现在我想动态检测这些较小的文件是否已被修改,而不是在代码中维护文件列表。我们之前只是缓存了我们大文件的 md5 副本。
  • @simgineer 您应该仔细阅读文件通知,因为它不仅在系统启动时触发。

标签: java md5 checksum


【解决方案1】:

这取决于你所说的“简单”。

一方面,您可以利用文件时间戳。但问题是时间戳可能会产生误导:

  • 根据时间戳进行的检查可能会受到时钟偏差问题的影响。 (这取决于涉及哪些时钟,以及如何管理时钟。)

  • 可能会重置文件时间戳(例如,由“root”用户),使文件看起来没有更改。

  • 在不实际更改文件的情况下更改“已修改”文件时间戳是微不足道的;例如touch

另一方面,如果您使用校验和,您还有其他问题:

  • 计算文件校验和需要读取整个文件。 (一般来说,部分校验和不足以检测更改。)一些校验和算法也相对昂贵。

  • 您还需要知道文件的先前校验和是什么。这意味着您需要一种方式/地方来存储它。这可能只是另一个文件,但作为同步过程的一部分,您需要一些基础架构来(可靠地)更新该文件。

  • 异或多个校验和的问题是您不知道哪些文件已更改。如果一个文件发生变化,您需要同步所有文件。

  • 理论上有可能文件发生变化而 MD5 校验和相同:2^128 中的概率 1。您可能会对此打折扣……除非您的应用程序是安全关键型应用程序。 (请注意,MD5 碰撞攻击在某些情况下是实用的;请参阅https://en.wikipedia.org/wiki/Collision_attack


另一件事是我怀疑您正在尝试解决已解决的问题。例如,Linux / Unix rsync 实用程序可以选择使用时间戳或 (MD5) 校验和来决定需要同步哪些文件。

您不需要自己实现所有内容(在 Java 中)。

针对您的“我们无权访问旧文件树”,有一个简单的解决方案。每次重启时:

  1. 复制文件树
  2. 将当前文件与您上次重新启动时制作的副本进行比较。

就像我在评论中所说,发挥你的想象力。

【讨论】:

  • 欣赏洞察力。顺便说一句 - 这不是文件同步方案。我们解析配置文件(很大),然后如果有更改,则会进行数据库更新(这需要时间)。这是一个遗留程序。使用 rsync 没有意义。
  • 您可以使用rsync 处理这个问题。只是需要一点想象力。或者,如果这不是(远程)文件系统同步问题,您可以简单地比较“旧”和“新”文件树中的文件。也有 Linux / UNIX 实用程序可以做到这一点。
  • 是的,如果您接受@StephenC 的建议,并且您至少使用 Java 12(我知道,这对于生产代码来说并不常见),您应该查看 Files.mismatch(Path, Path) 介绍的在 Java 12 中。
  • 嗨@StephenC 和Axel,我相信rsync 的建议要求原始目录结构可用,我们无法访问旧文件系统,我们从旧文件系统是重要文件的捕获或校验和。同步例程在旧配置文件被新配置文件覆盖后运行。为了澄清同步不是在两个文件系统之间,而是在一组配置文件和一个由 mysql 表支持的设置矩阵引擎之间。 xml 定义设置类型,数据库存储每个配置文件的数据。
【解决方案2】:

文件的修改时间对您的情况有用吗? Md5sum 在某些情况下是一种更精确的方法。

【讨论】:

  • 我认为我们更喜欢校验和或摘要而不是时间戳,以防系统时间设置不正确。
【解决方案3】:

这是我希望从目录中的所有文件生成哈希的例程。

/**
 * Recursively compute a single md5 signature of all files in a directory. Is typically 
 * used to determine if a file in a directory or any of the sub directories have been 
 * modified since the last digest was taken.
 */
public class DirectoryDigest {

    MessageDigest md = null;

    public DirectoryDigest() {
        try {
            md = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            ApplicationManager.logStackTrace(e);
        }
    }

    public void update(Path dirPath) {
        update(dirPath, null);
    }

    public synchronized void update(Path dirPath, String extension) {

        try {
            Files.newDirectoryStream(dirPath).forEach(file -> {
                if (!Files.isDirectory(file) && file.getFileName().toString().endsWith(extension)) {
                    if (extension != null && !file.getFileName().toString().endsWith(extension)) {
                        System.out.println("not processing: " + file.getFileName());
                        return;
                    }
                    try {
                        byte[] bytes = Files.readAllBytes(file);
                        md.update(bytes);
                    } catch (IOException e) {
                        ApplicationManager.logStackTrace(e);
                    }
                } else {
                    update(file, extension);
                }
            });
        } catch (IOException e) {
            ApplicationManager.logStackTrace(e);
        }
    }

    /**
     * Returns md5 digest signature and resets the digest object.
     * @return
     */
    public String digest() {
        return String.format("%032X", new BigInteger(1, md.digest()));
    }
}

它是这样使用的:

DirectoryDigest dd = new DirectoryDigest();
dd.update(csConfigDirPath, ".xml");
String currentPeripheralHash = dd.digest();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-03
    相关资源
    最近更新 更多