4

我正在尝试比较两个目录,以查看目录 1 中哪些文件不在目录 2 中。我有以下代码:

System.IO.DirectoryInfo dir1 = new System.IO.DirectoryInfo(pathA);
System.IO.DirectoryInfo dir2 = new System.IO.DirectoryInfo(pathB);

IEnumerable<System.IO.FileInfo> list1 = dir1.GetFiles("*.PRN");
IEnumerable<System.IO.FileInfo> list2 = dir2.GetFiles("*.PRN");

IEnumerable<System.IO.FileInfo> list3 = list1.Except(list2);

Console.WriteLine("The following files are in list1 but not list2:");

foreach (var v in list3)
{
    Console.WriteLine(v);
}
Console.WriteLine("Press any key to continue...");
Console.ReadKey();

当它运行时,它清楚地列出了目录 1 中的所有文件,但其中许多文件已经在目录 2 中。我只需通过 Windows 资源管理器查看文件名即可看到这一点。我错过了什么?

编辑:

我相信问题出在文件比较部分。我试图让它忽略文件扩展名的大小写。我试过这个:

    class FileCompare : System.Collections.Generic.IEqualityComparer<System.IO.FileInfo>
{
    public FileCompare() { }

    public bool Equals(System.IO.FileInfo f1, System.IO.FileInfo f2)
    {
        //return (f1.Name.ToUpper == f2.Name.ToUpper &&
        //        f1.Length == f2.Length);

        return (string.Equals(f1.Name, f2.Name, StringComparison.OrdinalIgnoreCase) && f1.Length == f2.Length);
    }

    public int GetHashCode(System.IO.FileInfo fi)
    {
        string s = String.Format("{0}{1}", fi.Name, fi.Length);
        return s.GetHashCode();
    }
}

但这仍然行不通。你可以看到我注释掉了另一个尝试,只是在比较中将所有内容都设为大写,但它不会那样做。

4

4 回答 4

7

您将需要使用的重载版本Except()并将其传递给它的自定义实现,IEqualityComparer该实现准确地指示您定义两个FileInfo对象完全匹配的标准。

请参阅此处的示例并根据自己的需要进行修改:http: //msdn.microsoft.com/en-us/library/bb336390.aspx

于 2013-05-08T19:53:09.143 回答
2

MSDN上有一个示例,向您展示了如何执行此操作。

创建你的IEqualityComparer实现

class FileCompare : System.Collections.Generic.IEqualityComparer<System.IO.FileInfo>
{
    public FileCompare() { }

    public bool Equals(System.IO.FileInfo f1, System.IO.FileInfo f2)
    {
        return (f1.Name == f2.Name &&
                f1.Length == f2.Length);
    }

    public int GetHashCode(System.IO.FileInfo fi)
    {
        string s = String.Format("{0}{1}", fi.Name, fi.Length);
        return s.GetHashCode();
    }
}

然后将Except重载与您的比较器一起使用。

var queryList1Only = (from file in list1
                      select file).Except(list2, myFileCompare);
于 2013-05-08T19:55:34.727 回答
1

由于您只对名称.Select感兴趣,因此使用LINQ的扩展方法将您的序列投影到名称序列:

IEnumerable<string> list1 = dir1.GetFiles("*.PRN").Select(fi => fi.Name);
IEnumerable<string> list2 = dir2.GetFiles("*.PRN").Select(fi => fi.Name);
IEnumerable<string> list3 = list1.Except(list2);

(您可以使用var, 隐式类型。)

这适用于默认相等比较器进行string序号和区分大小写的比较(不仅仅是FileInfo类附带的引用相等比较)。

于 2013-05-08T20:35:32.200 回答
0

你可以使用 LINQ

        var list3 = from c in list1
                    where !(from o in list2
                            select o.Name)
                           .Contains(c.Name)
                    select c;

也可能存在不同情况的问题

你可以试试

.Equals(c.Name, StringComparison.OrdinalIgnoreCase)

代替

.Contains(c.Name)

或者在比较之前将所有内容转换为小写。

于 2013-05-08T20:10:59.563 回答