目录内容是否发生变化?

4

如何检查一个目录是否在给定时间点后其内容发生了变化?

我不需要得到变化的具体信息,只需要确认它是否发生了变化。


将该目录复制到另一个位置,然后进行比较。或者只需检查文件的“mtime”。 - Sergio Tulentsev
这是一个充满大型资源的目录,所以复制它不是一个选择。那么没有指示更改的目录属性吗?我需要递归检查所有文件和子目录,并比较存在和mtime吗? - Undistraction
以下解决方案应该可行。只需存储并比较递归 glob() 调用的哈希值与相关目录即可。 - struthersneil
3个回答

2
在你希望开始监控的时间点,使用任何你喜欢的方法创建一个文件,例如:
touch time_marker

当您想要检查是否添加了任何内容时,请使用以下方式进行“查找”:

find . -newer time_marker

这将只告诉你自从创建time_marker以来修改或添加的文件 - 它不会告诉你是否删除了任何内容。如果您想在未来再次查看,请再次“touch” time_marker以创建新的参考点。


1
如果您只需要知道名称是否更改或文件是否已添加/删除,可以尝试以下操作:
Dir.glob('some_directory/**/*').hash

只需存储和比较哈希值。你可以通过调用ls或者使用代表目录结构中每个文件的File对象来获取更多信息,并对其进行哈希处理。

Dir.glob('some_directory/**/*').map { |name| [name, File.mtime(name)] }.hash
其实我太蠢了,哈希只对 Ruby 的任何一个运行环境一致。让我们使用标准的 Zlib::crc32 替代它。
Zlib::crc32(Dir.glob('some_directory/**/*').map { |name| [name, File.mtime(name)] }.to_s)

我担心这种方法会占用大量内存并且速度缓慢,如果你需要检查一个非常庞大的文件系统。也许整体匹配和映射不是最好的方法——如果你有很多子目录,可以递归地遍历它们并为每个目录计算校验和,然后将校验和组合起来。

对于较大的目录,这可能更好:

Dir.glob('some_directory/**/*').map do |name| 
  s = [name, File.mtime(name)].to_s
  [Zlib::crc32(s), s.length]
end.inject(Zlib::crc32('')) do |combined, x| 
  Zlib::crc32_combine(combined, x[0], x[1])
end

这样会更不容易碰撞:

Dir.glob('some_directory/**/*').map do |name| 
  [name, File.mtime(name)].to_s
end.inject(Digest::SHA512.new) do |digest, x| 
  digest.update x
end.to_s

这太棒了。谢谢。 - Undistraction
我发现这种方法存在一些奇怪的不一致性。如果我打开IRB并重复执行Dir.glob('some_directory/**/*').map { |name| [name, File.mtime(name)] }.hash,每次都会得到相同的值。但是,如果我关闭IRB,重新打开并再次执行相同的操作,我会得到一个不同的值(同样是重复的)。 - Undistraction
请稍等,我会调查一下。我原以为哈希对于任何给定的输入都是一致的。 - struthersneil
好的,我们需要生成一个CRC摘要。哈希只需要在任何给定的运行时环境中保持一致即可。(这就是为什么我喜欢在Stack Overflow上解决问题的原因。) - struthersneil
运行得非常好。目录结构相当简洁,因此没有性能问题。感谢您的帮助。 - Undistraction

0

我已经修改了这个程序,加入了时间戳和文件大小。

dir_checksum = Zlib::crc32(Dir.glob(
  File.join(dispatch, '/**/*')).map { |path|
    path.to_s + "_" + File.mtime(path).to_s + "_" + File.size(path).to_s
  }.to_s)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接