使用C#& LINQ如何找到重复的文件名?

时间:2017-02-06 20:47:04

标签: c# linq

我花了一些时间试图找到答案,我很接近,但仍然卡住了。

想象一下,您有以下文件夹和文本文件..

C:\dupfiles
C:\dupfiles\tarts
C:\dupfiles\tarts\moretarts

C:\dupfiles\tarts\lindsay.txt
C:\dupfiles\paris.txt
C:\dupfiles\britney.txt
C:\dupfiles\tarts\moretarts\britney.txt
C:\dupfiles\tarts\moretarts\paris.txt

我正在尝试运行显示重复项的LINQ查询(paris.txt& britney.txt)。在SQL中,您可以通过group by和having子句来执行此操作。

这是我到目前为止的代码......

using System;
using System.IO;
using System.Linq;

class Program
{
    public static void Main(string[] args)
    {
        String strPath = @"C:\dupfiles";

        var filelist = from file in Directory.GetFiles(strPath, "*", SearchOption.AllDirectories)
                       select file
                       into files
                       select Path.GetFileName(files);

        var duplicateNames = filelist.GroupBy(file => filelist)
                           .Where(group => group.Count() > 1)
                           .Select(group => group.Key);       

        foreach (var f in duplicateNames)
        {
            Console.WriteLine(f);
        }

        Console.WriteLine("Press <enter> to continue");
        Console.ReadLine();
    }
}

我不完全理解代码是如何工作的,结果并不完全是我正在寻找的。

这是输出......

System.Linq.Enumerable+WhereSelectArrayIterator`2[System.String,System.String]

在示例代码中,f是一种... System.Linq.Enumerable.WhereSelectArrayIterator

我错过了一块拼图。谁能帮我?

4 个答案:

答案 0 :(得分:3)

对于某些标准,例如易于维护和速度,LINQ不一定是最好的答案。

例如,您可以拥有Dictionary<string, List<string>>,其中包含文件名和重复项的路径:

static Dictionary<string, List<string>> GetDupes2(string baseDir)
{
    Dictionary<string, List<string>> files = new Dictionary<string, List<string>>();

    foreach (string f in Directory.EnumerateFiles(baseDir, "*.*", SearchOption.AllDirectories))
    {
        var fName = Path.GetFileName(f);
        if (files.ContainsKey(fName))
        {
            files[fName].Add(f);
        }
        else
        {
            files.Add(fName, new List<string> { f });
        }
    }

    return files;

}

键是文件名,值是文件的完整路径名列表。只需使用files.Where(f => (f.Value.Count > 1))即可获得重复项。

答案 1 :(得分:3)

其他答案都没问题。如果你想坚持查询语法,那么你可以这样:

var duplicateNames = from filePath in Directory.GetFiles(strPath, "*", SearchOption.AllDirectories)
                     group filePath by Path.GetFileName(filePath) into files
                     where files.Count() > 1
                     select files;

为了便于阅读,我个人会选择引入let条款:

var duplicateNames = from filePath in Directory.GetFiles(strPath, "*", SearchOption.AllDirectories)
                     let filename = Path.GetFileName(filePath)
                     group filePath by filename into files
                     where files.Count() > 1
                     select files;

let基本上是您在整个查询过程中可以访问的临时变量。

然后,您可以使用嵌套的foreach打印这些项目,如Joshua Miller所示。

答案 2 :(得分:2)

修改

  • 如果您正在寻找带有查询语法的答案,请查看 Kenneth K's answer
  • 如果您有很多的文件需要通过,因此需要有效的解决方案,我建议您检查 out Andrew Morton's answer
  • 此答案提供有关打印的建议。

此答案还将写入所有重复项的完整文件路径。

var strPath  = @"YourPath";

var dupeFiles = Directory.GetFiles(strPath , "*", SearchOption.AllDirectories)
    .Select(fullPath => new
    {
        Name = Path.GetFileName(fullPath),
        FullPath = fullPath
    })
    .GroupBy(file => file.Name)
    .Where(fileGroup => fileGroup.Count() > 1);

foreach (var dupeGroup in dupeFiles)
{
    Console.WriteLine(dupeGroup.Key);
    foreach (var dupeFile in dupeGroup)
    {
        Console.WriteLine($"   {dupeFile.FullPath}");   
    }
}

它通过使用anonymous type来实现这一点。

如上所述,这将导致输出显示重复文件的标题以及所有重复项的完整路径,类似于下面的示例输出。

dupe.txt
   C:\Users\testUser\Desktop\Temp\dupe.txt
   C:\Users\testUser\Desktop\Temp\tarts\dupe.txt
dupe2.txt
   C:\Users\testUser\Desktop\Temp\dupe2.txt
   C:\Users\testUser\Desktop\Temp\tarts\dupe2.txt

答案 3 :(得分:1)

此代码按组Key过滤文件名,并选择包含文件名的string[] duplicitNames = Directory.GetFiles(strPath, "*", SearchOption.AllDirectories) .Select(f => Path.GetFileName(f)) .GroupBy (f => f) .Where (g => g.Count () > 1) .Select (g => g.Key) .ToArray();

IGrouping<TKey, TElement>

为了更好地理解,代码可以分为两部分,例如像这样g接口表示具有公共密钥的对象的集合。 IEnumerable<IGrouping<string, string>> groupedFileNames = Directory.GetFiles(strPath, "*", SearchOption.AllDirectories) .Select(f => Path.GetFileName(f)) .GroupBy (f => f); string[] duplicitNames = groupedFileNames .Where (g => g.Count () > 1) .Select (g => g.Key) .ToArray(); 就是这样一个分组。 HTH

IEnumerable

注意:IGrouping的签名如下所示,您可以看到它Count来自public interface IGrouping<out TKey, out TElement> : IEnumerable<TElement>, IEnumerable

$messages = array(); try { $opt_param = array( 'maxResults' => 100, 'labelIds' => 'INBOX' ); $messagesResponse = $service->users_messages->listUsersMessages($userId, $opt_param); $messages = $messagesResponse->getMessages(); } catch (Exception $e) { print 'An error occurred: ' . $e->getMessage(); } if(!empty($messages)) { foreach ($messages as $message) { print 'Message with ID: ' . $message->getId() . '<br/>'; } } return $messages;