C# 如何确定文件是否已被修改?
我正在写(某种)备份解决方案。只需将文件从位置C:\复制并粘贴到位置Z:\ 为确保速度快,在复制和粘贴之前,请检查原始文件是否存在。如果是这样,它会执行一些“计算”,以确定复制是否应该继续,或者备份文件是否是最新的。我发现这些计算很困难 最初,我比较了文件大小,但这还不够好,因为很可能会更改文件,使其大小相同(例如,在记事本中保存字符C的大小与保存字符T的大小相同) 因此,我需要找出修改日期是否不同。目前,我使用C# 如何确定文件是否已被修改?,c#,C#,我正在写(某种)备份解决方案。只需将文件从位置C:\复制并粘贴到位置Z:\ 为确保速度快,在复制和粘贴之前,请检查原始文件是否存在。如果是这样,它会执行一些“计算”,以确定复制是否应该继续,或者备份文件是否是最新的。我发现这些计算很困难 最初,我比较了文件大小,但这还不够好,因为很可能会更改文件,使其大小相同(例如,在记事本中保存字符C的大小与保存字符T的大小相同) 因此,我需要找出修改日期是否不同。目前,我使用FileInfo类获取文件信息,但在查看了所有字段后,似乎没有任何适合的内容 如何检
FileInfo
类获取文件信息,但在查看了所有字段后,似乎没有任何适合的内容
如何检查以确保复制已修改的文件
编辑
我已经看到了关于使用MD5校验和的建议,但我担心这可能是一个问题,因为我正在比较的一些文件将高达10GB,您可能想查看该类 “此类允许您监视目录的更改,并将触发 修改某些内容时发生的事件。“ 然后,代码可以处理事件并处理文件 代码源-MSDN:
// Create a new FileSystemWatcher and set its properties.
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = args[1];
/* Watch for changes in LastAccess and LastWrite times, and
the renaming of files or directories. */
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
// Only watch text files.
watcher.Filter = "*.txt";
// Add event handlers.
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.Created += new FileSystemEventHandler(OnChanged);
watcher.Deleted += new FileSystemEventHandler(OnChanged);
watcher.Renamed += new RenamedEventHandler(OnRenamed);
按修改后的日期走是不可靠的——当计算机时钟同步或手动调整时,时钟可能会倒转。在管理修改日期方面,某些程序在修改或复制文件时可能表现不佳 使用归档位可能在受控环境中工作,但如果运行的另一个软件也使用归档位,会发生什么情况 如果您希望(几乎)完全可靠,那么您应该使用良好的散列函数(如SHA1)存储上次备份版本的散列值,如果散列值发生更改,则上载新副本 下面是SHA1类以及底部的代码示例: 只需运行文件字节并存储哈希值。将
FileStream
传递给它,而不是使用字节数组将文件加载到内存中,以减少内存使用,特别是对于大型文件
您可以通过各种方式将其与修改日期相结合,根据需要调整程序,以提高速度和可靠性。例如,您可以检查大多数备份的修改日期,并定期运行在系统空闲时运行的哈希检查程序,以确保没有遗漏任何内容。有时修改的日期会改变,但文件内容仍然相同(即被相同的数据覆盖),在这种情况下,您可以避免在重新计算哈希并意识到它仍然相同后重新发送整个文件
大多数版本控制系统使用某种结合哈希和修改日期的方法
如果您不想执行完整备份并每次发送所有数据,您的方法通常会涉及某种风险管理,在性能和可靠性之间进行折衷。出于这个原因,偶尔进行一次“完整备份”非常重要。您可以通过散列来比较文件:
private byte[] GetFileHash(string fileName)
{
HashAlgorithm sha1 = HashAlgorithm.Create();
using(FileStream stream = new FileStream(fileName,FileMode.Open,FileAccess.Read))
return sha1.ComputeHash(stream);
}
如果内容发生了更改,哈希值将不同。一般来说,您应该让操作系统负责跟踪文件是否发生了更改 如果您使用:
File.GetAttributes
并检查存档标志,这将告诉您自上次存档以来该文件是否已更改。我相信XCOPY和类似软件在完成复制后会重置此标志,但您可能需要自己处理此问题
您可以使用以下方法在DOS中轻松测试标志:
dir /aa yourfilename
或者只需在windows资源管理器中添加属性列。备份程序通常使用文件存档标志来检查文件是否需要备份。Windows修改或创建文件时,会设置存档标志(请参见)。检查是否设置了存档标志以决定文件是否需要备份:
if ((File.GetAttributes(fileName) & FileAttributes.Archive) == FileAttributes.Archive)
{
// Archive file.
}
备份文件后,清除存档标志:
File.SetAttributes(fileName, File.GetAttributes(fileName) & ~FileAttributes.Archive);
这假设没有其他程序(如系统备份软件)清除存档标志。大多数文件系统都有一个很好的元属性,通常称为“上次修改时间”。FileInfo.LastWriteTime没有此信息吗?这就是我从这个问题中得到的印象:也许这会有所帮助:@DaveRook关于这个问题的其他一些答案可能值得一看。:-)没有其他方法可以检查文件中的任何字节是否可能已被更改,除了逐字节比较两个文件,这可能会更慢。我的程序不设计为全天候查看文件夹,只动态检查两个文件(在复制/粘贴时)。所以+1作为一个很好的信息和有用的替代方案,但我希望比较2个文件。仅供参考,这似乎不是一个单声道兼容的解决方案。我查看了源代码,发现有一个while循环在持续运行。它不会让处理器忙或开销大吗?操作系统是如何管理的?为了清楚起见,当你说存储散列时,你是指在外部文件或数据库(或类似的)中吗?这取决于你的系统是如何实现的:)你可以保留一个值数据库,或者,您可以执行subversion以前的操作,在备份位置内创建一个隐藏目录,其中包含所有备份文件的哈希值。Subversion不再这样做了,现在只在版本目录结构的根目录中将数据库保存在一个隐藏目录中。感谢您花时间提供帮助。这对于源代码/文档来说很好,但对于大型二进制文件等来说还不够快。这取决于您如何定义“足够快”——对于每周或夜间无人值守的备份过程,在空闲时间内完成,在合理的amo中甚至可以处理100GB的数据