我一直在尝试创建一个小程序来比较两个字符串集合,并输出collection1和collection2之间不同或缺失的任何项。
到目前为止,我已经能够确定LINQ的. except方法应该提供我想要的结果,但它似乎不足。
我试图比较的文件是使用ICACLS生成的ACL文件,通过从cmd运行以下命令来保存给定目录及其子目录上的所有权限:
icacls c:TestHash /save c:aclFile.txt /t
我在一个目录上运行这个命令两次,以产生两个我想要确保匹配的icacls文件,如果它们不匹配,那么我想输出它们不匹配的地方。
下面是一些示例代码,用于比较这些项
//Load in user permissions files
var list1 = File.ReadAllLines(dbFilePath1, Encoding.Unicode);
var list2 = File.ReadAllLines(dbFilePath2, Encoding.Unicode);
一旦条目被加载,我将运行。except命令
//Identify all differences between the two collections and output to new collection
var list3 = list1.Except(list2);
var list4 = list2.Except(list1);
然而,下面是一个来自文件1的10条记录的例子,我从文件2中删除了一条权限记录,但是。except没有识别它缺少
项第一个文件:
TestHash
D:AI(A;OICIID;FA;;;BC)(A;OICIID;FD;;;SY)(A;OICIID;0x1200a9;;;BU)(A;ID;0x1307by;;;AU)(A;OICIIOID;SDGXGWGR;;;AU)
TestHashtestFile1.csv
D:AI(A;ID;FA;;;BD)(A;ID;FR;;;SY)(A;ID;0x1200a9;;;BU)(A;ID;0x1307by;;;AU)
TestHashtestFile2.csv
D:AI(A;ID;FA;;;BD)(A;ID;FR;;;SY)(A;ID;0x1200a9;;;BU)(A;ID;0x1307by;;;AU)
TestHashtestFile3.csv
D:AI(A;ID;FA;;;BD)(A;ID;FR;;;SY)(A;ID;0x1200a9;;;BU)(A;ID;0x1307by;;;AU)
TestHashtestFile4.csv
D:AI(A;ID;FA;;;BD)(A;ID;FR;;;SY)(A;ID;0x1200a9;;;BU)(A;ID;0x1307by;;;AU)
第二文件:TestHash
D:AI(A;OICIID;FA;;;BC)(A;OICIID;FD;;;SY)(A;OICIID;0x1200a9;;;BU)(A;ID;0x1307by;;;AU)(A;OICIIOID;SDGXGWGR;;;AU)
TestHashtestFile1.csv
D:AI(A;ID;FA;;;BD)(A;ID;FR;;;SY)(A;ID;0x1200a9;;;BU)(A;ID;0x1307by;;;AU)
TestHashtestFile2.csv
D:AI(A;ID;FA;;;BD)(A;ID;FR;;;SY)(A;ID;0x1200a9;;;BU)(A;ID;0x1307by;;;AU)
TestHashtestFile3.csv
TestHashtestFile4.csv
D:AI(A;ID;FA;;;BD)(A;ID;FR;;;SY)(A;ID;0x1200a9;;;BU)(A;ID;0x1307by;;;AU)
如上所述,第二个文件缺少一个权限记录,但是。除了不识别这一点,集合正在作为字符串的枚举进行处理,默认的相等比较器应该能够检测到这种差异,据我所知,我知道你可以用自定义比较器覆盖这一点,但我不确定实现将是什么。
另一个注意事项是,这似乎只抛出任何权限字符串本身的问题,除了似乎能够确定任何缺失的字符串,当它是文件夹/文件名之一,所以我认为它可能会感到困惑,因为有许多相同的权限字符串在集合内,所以它可能认为它有一个匹配的项目,即使它没有一个特定的记录与特定的文件。
我预计这将需要某种自定义覆盖,但我不确定这个实现将是什么。
任何想法都将非常感激,感谢您花时间阅读这篇文章。
我不确定我的假设是否正确,但是看起来生成的文件的格式是每个目录条目两行,并且第一行是文件的完整路径,因此必须是唯一的。
如果正确,则第二个列表不能包含TestHashtestFile3.csv
行。
如果是,那么您可以将目录条目与权限分组,然后使用except检查差异。
为此,我首先为每行添加行号,然后按每两行分组,然后创建一个匿名对象,其中包含每组中的第一个和第二个条目
如
var groupedList1 = list1
.Select((val , index) => new { val, index })
.GroupBy(g => g.index / 2)
.Select(r => r.ToArray())
.Select(r => new { DirectoryEntry = r[0].val , OldPermission = r[1].val , NewPermission = ""}) ;
因为DirectoryEntry Name是唯一的,所以我们知道分组列表中的每个条目必须是唯一的,因此except操作符将按照您的需要进行操作。
或者像
一样组合groupedList1和groupedList2var allEntries = groupedList1.Select(a=>a.DirectoryEntry).Union(
groupedList2.Select(a=>a.DirectoryEntry));
var combined = (from r in allEntries select new
{
DirectoryEntry = r ,
OldPermission = groupedList1.SingleOrDefault(a=>a.DirectoryEntry == r)?.Permission ,
NewPermission = groupedList2.SingleOrDefault(a=>a.DirectoryEntry == r)?.Permission
}
)
.Where(a=>a.OldPermission != a.NewPermission);