我正在做一个项目。我必须比较两个文件的内容,看看它们是否完全匹配。

在进行大量的错误检查和验证之前,我的第一稿是:

  DirectoryInfo di = new DirectoryInfo(Environment.CurrentDirectory + "\\TestArea\\");
  FileInfo[] files = di.GetFiles(filename + ".*");

  FileInfo outputFile = files.Where(f => f.Extension == ".out").Single<FileInfo>();
  FileInfo expectedFile = files.Where(f => f.Extension == ".exp").Single <FileInfo>();

  using (StreamReader outFile = new StreamReader(outputFile.OpenRead()))
  {
    using (StreamReader expFile = new StreamReader(expectedFile.OpenRead()))
    {
      while (!(outFile.EndOfStream || expFile.EndOfStream))
      {
        if (outFile.ReadLine() != expFile.ReadLine())
        {
          return false;
        }
      }
      return (outFile.EndOfStream && expFile.EndOfStream);
    }
  }

嵌套using语句似乎有点奇怪。

还有更好的办法吗?


当前回答

如果你想要有效地比较文件,根本就不要使用streamreader,这样使用就没有必要了——你可以使用低级流读取来拉入数据缓冲区进行比较。

您还可以首先比较文件大小等内容,以快速检测不同的文件,从而节省自己读取所有数据的时间。

其他回答

为了增加清晰度,在这种情况下,因为每个连续的语句都是一个语句(而不是一个块),你可以省略所有的括号:

using (StreamReader outFile = new StreamReader(outputFile.OpenRead()))
  using (StreamReader expFile = new StreamReader(expectedFile.OpenRead()))
    while (!(outFile.EndOfStream || expFile.EndOfStream))  
       if (outFile.ReadLine() != expFile.ReadLine())    
          return false;  

这没什么奇怪的。使用是一种确保在代码块完成后处理对象的简便方法。如果你的外块中有一个内块需要使用的一次性物体,这是完全可以接受的。

最好的方法是在最后一个using语句之后只放一个左大括号{,就像这样:

using (StreamReader outFile = new StreamReader(outputFile.OpenRead()))
using (StreamReader expFile = new StreamReader(expectedFile.OpenRead())) 
{
    ///...
}

如果你不介意在using块之前声明using块的变量,你可以在同一个using语句中声明它们。

    Test t; 
    Blah u;
    using (IDisposable x = (t = new Test()), y = (u = new Blah())) {
        // whatever...
    }

这样的话,x和y只是用于using块的IDisposable类型的占位符变量,你可以在代码中使用t和u。我只是想提一下。

如果你想要有效地比较文件,根本就不要使用streamreader,这样使用就没有必要了——你可以使用低级流读取来拉入数据缓冲区进行比较。

您还可以首先比较文件大小等内容,以快速检测不同的文件,从而节省自己读取所有数据的时间。