【问题标题】:How to read files from each subfolder by giving preference to inner environment folder first in c#?如何通过在c#中优先选择内部环境文件夹来从每个子文件夹中读取文件?
【发布时间】:2020-08-31 21:34:38
【问题描述】:

我有这样的文件夹结构 -

Products
├── folder1
│   ├── files1.json
│   ├── files2.json
│   └── files3.txt
├── folder2
│   ├── files4.json
│   ├── files5.json
│   └── files6.txt
└── folder3
    ├── files10.json
    ├── files7.json
    ├── files8.json
    └── files9.txt

我有一个根文件夹Products,然后里面有一堆子文件夹。这些子文件夹中的每一个都有一堆文件。为简单起见,我想出了子文件夹名称为folder{number},文件名称为files{number}.json.txt,但通常它们有不同的名称。一般来说,我在根文件夹中有 20 个不同的子文件夹,每个子文件夹最多有大约 30 个文件。

以下是读取上述文件夹结构并从中读取所有文件的代码。在下面的代码中,path 变量具有 Products 值,即根文件夹名称。

private IList<string> ReadFiles(string path)
{
    var jsonFiles = Directory.GetFiles(path, "*.json", SearchOption.AllDirectories);
    var textFiles = Directory.GetFiles(path, "*.txt", SearchOption.AllDirectories);
 
    var allFiles = new List<string>(jsonFiles);
    allFiles.AddRange(textFiles);
    return allFiles;
}

问题陈述

现在我必须以不同的格式更改我的文件夹结构,如下所示:

Products
├── folder1
│   ├── dev
│   │   └── files1.json
│   ├── files1.json
│   ├── files2.json
│   ├── files3.txt
│   ├── prod
│   │   └── files1.json
│   └── stage
│       └── files1.json
├── folder2
│   ├── dev
│   │   └── files5.json
│   ├── files4.json
│   ├── files5.json
│   ├── files6.txt
│   ├── prod
│   │   └── files5.json
│   └── stage
│       └── files5.json
└── folder3
    ├── files10.json
    ├── files7.json
    ├── files8.json
    └── files9.txt

例如 - 在 folder1 子文件夹中,还有三个子文件夹 devstageprod,其他子文件夹 folder2folder3 完全相同。每个子文件夹中的 devstageprod 子文件夹中的每个子文件夹都将包含为其覆盖的文件。

现在我需要以这样一种方式更新我的上述代码,以便当它从 Products 根文件夹读取文件时,它应该将每个子文件夹的 dev 文件夹中的任何内容作为首选(意思是如果相同的文件存在于子文件夹级别,则应覆盖),然后应从相应的子文件夹中获取其他所有文件(其他文件)。因此,例如,这应该是它应该从上述示例的每个子文件夹中读取所有文件的方式 -

对于文件夹 1 -

  • 应该从 folder1 的 dev 文件夹中读取 files1.json
  • 它应该从 folder1 级别读取files2.json
  • 它应该从 folder1 级别读取files3.txt

对于文件夹 2 -

  • 它应该从 folder2 的 dev 文件夹中读取 files5.json
  • 它应该从文件夹 2 级别读取 files4.json
  • 它应该从文件夹 2 级别读取 files6.txt

对于文件夹 3,它应该只读取该级别的所有文件,因为它没有任何特定于环境的文件夹。

我应该如何修改我上面的C# 代码,以便它可以首先为每个子文件夹的dev 文件夹中的所有文件提供首选项/优先级,然后是它可以从相应的子文件夹层次结构中读取的剩余文件。

【问题讨论】:

  • 所以你说你不再喜欢 SearchOption.AllDirectories。如果发生这种情况,请改用 Directory.EnumerateFiles() 并根据需要进行递归。
  • “给予优先”是什么意思?
  • @JonathanWood 例如,如果file1 存在于folder1 级别内,并且我们在dev 文件夹内有相同的file1 folder1 但内容完全不同,所以我的代码应该使用@来自folder1dev 文件夹的987654354@ 不是来自folder1 级别的file1。这就是偏好在这里的基本含义。如果这没有意义,请告诉我。
  • 创建一个类/结构,它具有文件的完整路径以及额外的属性。 a) 布尔值是否在 dev 文件夹中。 b) “已调整”路径 - 与完整路径相同,但如果存在 dev,则将其删除。现在将所有文件添加到List&lt;YourNewType&gt;。现在创建一个Dictionary&lt;string, YourNewType&gt;。按 a) 布尔值降序排列您的列表(即首先有 dev 的)并将它们按顺序(如果它们不存在)添加到字典中,由 b 键控)。净效应 - 您想要在字典中的所有文件,优先考虑开发文件(首先添加)。
  • 我发现这个问题过于宽泛,更像是“为我编写代码”之类的问题。这里的根本问题是您没有编写任何会排除文件的代码,所以当然没有文件被排除在外。次要问题是您同时检索所有文件,因此您没有方便的方法来区分在“dev”目录中找到的文件,甚至是在其他“环境”目录中找到的文件。你应该从编写一个真正的规范开始。您在此处发布的只是一些示例,并非规范。

标签: c# linq file asp.net-core


【解决方案1】:

我应该如何修改我上面的 C# 代码,以便它可以提供 每个 dev 文件夹中所有文件的首选项/优先级 首先是子文件夹,然后是可以从中读取的剩余文件 相应的子文件夹层次结构。

要做到这一点,你只需要添加一些逻辑代码。

首先获取Products文件夹下three-level folder的名称,然后通过判断是否包含dev文件夹的名称来确定如何将文件添加到allFiles中。 p>

如果是,使用SequenceEqual方法比较dev中的文件和文件夹下的文件,如果内容相同,添加dev中的文件。如果没有dev文件夹,直接将该文件夹下的文件添加到allFiles中。

更新

这里是逻辑代码:

 private static List<string> ReadFiles(string path)
   { 
            var allFiles = new List<string>();
            var subFolders = Directory.EnumerateDirectories(path).ToList();
            var fileType = new List<string>() { "*.json", "*.txt" };
            for (int i = 0; i < fileType.Count; i++)
            {
                foreach (var sub in subFolders)
                {
                    var subSubFolders = Directory.EnumerateDirectories(sub).ToList();
                    var jsonFiles = Directory.GetFiles(sub, fileType[i], SearchOption.AllDirectories).Where(x => !subSubFolders.Any(y => x.Contains(y))).ToList();
                    var subDev = Directory.GetFiles(sub, fileType[i], SearchOption.AllDirectories).Where(x => x.Contains("dev")).ToList();
                    foreach (var item in jsonFiles)
                    {
                        var dd = subDev.Where(x => (Path.GetFileName(x) == Path.GetFileName(item))).FirstOrDefault();
                        allFiles.Add(dd == null ? item : dd);
                    }
                    var extraFileDev = subDev.Where(x => !jsonFiles.Any(y => y.Contains(Path.GetFileName(x)))).ToList();
                    foreach (var item in extraFileDev)
                    {
                        allFiles.Add(item);
                    }
                }
            }
            return allFiles;
        }

【讨论】:

  • 感谢您的建议。我试过你的例子,但我看到了一些问题。我用这个问题和我尝试的方法更新了我的问题。如果我做错了什么,你能看看并告诉我吗?当我以某种方式运行您的示例时,它没有来自 dev 文件夹的文件,并且它还包括我不想要的阶段和产品文件。
  • @cs98,很抱歉我没有考虑到prodstage 文件夹,我理解了一些问题,但我已经更新了代码并测试了所有内容可能和我一起。我认为更新后的代码正是你想要的,希望对你有所帮助。
  • 非常感谢。我会尝试一下,但我很好奇我们是否需要在RemoveAll 行中添加stageprod 名称作为常量来删除它?它不能以这样的方式完成,以便只考虑dev 文件夹和folder1folder2 或....folderx 内的所有其他内部环境子文件夹将被自动删除?假设将来如果我还想删除其他一些环境文件夹,那么我不想更改此代码以添加该环境文件夹常量。如果它可以按原样工作,那就太好了。让我知道这是否有意义
  • 好的,我尝试了你的代码,我注意到还有一件事,除此之外它看起来不错 - 我可能在每个环境文件夹(开发或阶段或产品)中都有一些新文件上层子文件夹中不存在,所以我想在最终列表中也带来新的开发文件。例如-假设我们有一个folder4,它有文件35和36,然后在folder4dev文件夹内有一个文件38,那么在最终列表中我想要那个文件38以及35和36 .
  • 创意是 dev 文件夹中的任何内容,它应该出现在最终列表中。如果 dev 中的文件与子文件夹级别中的文件相同,那么它将覆盖该文件,否则无论如何它都是一个新文件,因此它应该出现在最终列表中。
【解决方案2】:

这个查询对我有用:

IEnumerable<string> query =
    from directory in System.IO.Directory.EnumerateDirectories(products) //1
    let dev = System.IO.Path.Combine(directory, "dev") //2
    from file in System.IO.Directory.EnumerateFiles(directory) //3
    let fi = new System.IO.FileInfo(file) //4
    let dev_file = System.IO.Path.Combine(dev, fi.Name) //5
    select System.IO.File.Exists(dev_file) ? dev_file : file; //6
  1. 获取“产品”路径中的每个子文件夹 - folder1、folder2、folder3
  2. 为可能的“dev”子文件夹创建路径
  3. 从当前文件夹中获取每个文件
  4. 获取文件的 System.IO.FileInfo 对象
  5. 在“dev”子文件夹中为可能的匹配文件创建路径
  6. 如果 dev 子文件夹文件存在,则使用该文件,否则使用常规文件

我明白了:

...\Products\folder1\dev\file1.txt 
...\Products\folder1\file2.txt 
...\Products\folder1\file3.txt 
...\Products\folder2\file4.txt 
...\Products\folder2\dev\file5.txt 
...\Products\folder2\file6.txt 
...\Products\folder3\file10.txt 
...\Products\folder3\file7.txt 
...\Products\folder3\file8.txt 
...\Products\folder3\file9.txt 

根据您的 cmets 下面的查询有效:

IEnumerable<string> query =
    from directory in Directory.EnumerateDirectories(products)
    let dev = Path.Combine(directory, "dev")
    from ext in new [] { "txt", "json" }
    from file in 
        Enumerable
            .Concat(
                Directory.Exists(dev)
                    ? Directory.EnumerateFiles(dev, $"*.{ext}")
                    : Enumerable.Empty<string>(),
                Directory.EnumerateFiles(directory, $"*.{ext}"))
            .Select(f => new FileInfo(f))
            .GroupBy(f => f.Name)
            .SelectMany(x => x.Take(1))
            .Select(x => x.FullName)
    select file;

我明白了:

...\Products\folder1\dev\file1.txt 
...\Products\folder1\dev\file42.txt 
...\Products\folder1\file2.txt 
...\Products\folder1\file3.txt 
...\Products\folder1\dev\file84.json 
...\Products\folder1\file4.json 
...\Products\folder2\dev\file5.txt 
...\Products\folder2\file4.txt 
...\Products\folder2\file6.txt 
...\Products\folder3\file10.txt 
...\Products\folder3\file7.txt 
...\Products\folder3\file8.txt 
...\Products\folder3\file9.txt 

【讨论】:

  • 有趣的解决方案。我是 C# 新手,只有一个月大。你能告诉我上面的代码是如何工作的吗?我认为它不会正确编译?
  • @cs98 - 它编译得很好。我在发布之前测试了所有代码。您可能只需要引用 System.IO 命名空间。
  • @cs98 - products 是您的“产品”文件夹的路径。
  • 是的,我试过了,它适用于我的上述情况,但不适用于这种情况。思路是如果dev中的文件与subFolder下的文件同名,不管内容是否相同,都应该选择dev中的文件,并显示在最终列表中。因此,如果 dev 中的文件是新文件并且它不存在于 subFolder 级别,则应将其添加到最终列表中,但如果 dev 中的文件与子文件夹级别相同,那么我将从子文件夹级别忽略该文件,但将 dev 文件添加到最终名单。
  • 例如,如果在文件夹 4 中,如果我有文件 35 和 36,但在 dev 文件夹中我有文件 38,那么在我的最终列表中,我还想要来自 dev 的 file38 以及文件 35 和文件 36
猜你喜欢
  • 2020-12-20
  • 2022-11-26
  • 2022-01-13
  • 2015-06-04
  • 2022-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多