C# - 比较两个文本文件

6

背景

我正在开发一个简单的Windows服务,用于监视某些目录的文件创建事件并记录这些事件——长话短说,以确定文件是否从A目录复制到B目录。如果X时间后在B目录中没有发现文件,就会发出警报。

这个问题是,我只有文件来判断它是否已经到达B目录。我假设两个具有相同名称的文件相同,但由于有60多个A目录和一个B目录,任何A目录中的文件可能会意外地与另一个A目录中的文件相同(按日期或顺序),因此这是不安全的假设……

例子

比方说,我存储了一个日志,指出文件“E17999_XXX_2111.txt”在目录C:\Test中被创建。我将存储文件名、文件路径、文件创建日期、文件长度和此文件的BOM。

30秒后,我检测到文件“E17999_XXX_2111.txt”在目录C:\FinalDestination中被创建……现在我需要确定:

a)该文件是否与C:\Test中创建的文件相同,因此我可以将第一个日志更新为完成并停止关注它。

b)该文件不相同,而我错过了之前的步骤——因此我可以忽略这个文件,因为它已经到达目的地目录。

研究

所以,为了确定在目的地创建的文件与最初创建的文件完全相同,我做了一些研究并找到了以下选项:

a)文件名比较

b)长度比较

c)创建日期比较

d)逐字节比较

e)哈希值比较

问题

a)如上所述,仅凭文件名太过自作聪明。

b)同样,仅凭文件内容的长度相同,并不意味着文件实际相同。

c)这种方法的问题是,复制后的文件就成为新文件,因此创建日期也会改变。无论文件出现在A目录和B目录之间的时间有多长,我都希望将第一个日志设置为已完成。

d)除了这种方法极其缓慢外,如果第二个文件的编码发生了变化——例如从ANSII到ASCII,那么像ASCII引号这样的东西就会导致字节不匹配。

我不想假设只是因为一个ASCII '变成了ANSII ',那么文件现在就不同了,因为它们几乎是相同的。

e)这似乎与逐字节比较有相同的缺点。

编辑

我遇到的实际问题似乎在于目录之间编码差异的原因-当前我无法访问处理此部分的代码,因此我无法确定为什么会发生这种情况,但我正在寻找一种解决方案,可以比较文件而不考虑编码来确定“真正”的差异(即不是由于编码而更改了字节的差异)。 解决方案 我现在已经通过使用SequenceEqual比较解决了这个问题,在将我的文件编码以删除任何错误数据后进行比较,如果由于此原因@Magnus建议的初始比较未能找到匹配项,则可以使用以下代码:
byte[] bytes1 = Encoding.Convert(Encoding.GetEncoding(1252), Encoding.ASCII, Encoding.GetEncoding(1252).GetBytes(File.ReadAllText(FilePath))); 
byte[] bytes2 = Encoding.Convert(Encoding.GetEncoding(1252), Encoding.ASCII, Encoding.GetEncoding(1252).GetBytes(File.ReadAllText(FilePath))); 

if (Encoding.ASCII.GetChars(bytes1).SequenceEqual(Encoding.ASCII.GetChars(bytes2)))
    { 
    //matched! 
    } 

感谢你的帮助!

现在无法详细说明,但是“慢”是相对的。.net框架非常擅长进行字符串比较,并且您可以将它们转换为本地字符串,这些字符串将是可比较的。我会选择A + B + D。按照这个顺序。每个失败都会使后续测试失效。将其读取为字符串以执行D。 - willaien
更改的编码是否是实际可能发生的真正问题?如果是,只需确保它不会发生。 - Magnus
@Magnus,确实发生了,这完全出乎意料,我目前不知道是什么原因导致的,但由于我正在尝试为各种代码库提供一种一刀切的解决方案,我希望能够想出一种解决方案,无论编码如何都可以解决这个问题-我研究了如何确定文件的编码,并找到了这个https://dev59.com/bW865IYBdhLWcg3wat6l#19283954,但无法找到一种方法将所有文件转换为相同的格式进行比较...有什么建议吗? - Danny Lager
@DannyLager StreamReader 会自动检测所使用的编码。 - Magnus
@Magnus 我个人没有尝试使用 StreamReader 来检测编码,但根据我所见和上面提到的链接,它似乎不是非常准确? - Danny Lager
显示剩余2条评论
1个回答

6

如果文件存在,您需要比较文件中的字符串内容。 StreamReaderReadLines使用的)应该检测编码。

var areEquals = System.IO.File.ReadLines("c:\\file1.txt").SequenceEqual(
                System.IO.File.ReadLines("c:\\file2.txt"));

请注意,ReadLines不会将完整的文件读入内存。

谢谢,我会尽可能尝试这个。无论编码方式如何,它是否返回true,因为我们正在比较两个字符串字面量,还是像逐字节比较一样? - Danny Lager
刚刚尝试了一下解决我遇到的问题,使用UTF8编码对两个文件进行比较 - File.ReadLines(FilePath1, Encoding.UTF8).SequenceEqual(File.ReadLines(FilePath2, Encoding.UTF8)) - 结果返回false,但是文件中唯一的区别只是引号,所以我认为这仍然会导致错误...有什么建议可以解决这个问题吗?运行速度非常快,这是一个积极的方面... - Danny Lager
也许引号字符实际上是不同的,而不是编码问题。 - Magnus
结果发现,如果我发现最初的比较失败,我必须重新阅读两个文件,然后将它们转换为ASCII编码,然后再进行上述比较。 - Danny Lager

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