首页 > 其他分享 >Linq与文件系统:使用 LINQ 查询文件和目录(上)

Linq与文件系统:使用 LINQ 查询文件和目录(上)

时间:2024-12-03 12:33:59浏览次数:6  
标签:startFolder Console WriteLine 文件系统 Linq Length LINQ file var

许多文件系统操作实质上是查询,因此非常适合使用 LINQ 方法。 这些查询是非破坏性的。 它们不会更改原始文件或文件夹的内容。 查询不应造成任何副作用。 通常,修改源数据的任何代码(包括执行创建/更新/删除操作的查询)应与仅查询数据的代码分开。

创建准确表示文件系统的内容并适当处理异常的数据源存在一定难度。 本部分中的示例创建 FileInfo 对象的快照集合,该集合表示指定的根文件夹及其所有子文件夹下的所有文件。 每个 FileInfo 的实际状态可能会在开始和结束执行查询期间发生更改。 例如,可以创建 FileInfo 对象的列表来用作数据源。 如果尝试通过查询访问 Length 属性,则 FileInfo 对象会尝试访问文件系统来更新 Length 的值。 如果该文件不再存在,则会在查询中收到 FileNotFoundException,即使未直接查询文件系统也是如此。

1、如何查询具有指定特性或名称的文件

此示例演示了如何在指定目录树中查找具有指定文件扩展名(如“.txt”)的所有文件。 它还演示了如何基于时间在树中返回最新或最旧的文件。 无论是在 Windows、Mac 还是 Linux 系统上运行此代码,都可能需要修改许多示例的第一行。

string startFolder = """C:\Program Files\dotnet\sdk""";
// Or
// string startFolder = "/usr/local/share/dotnet/sdk";

DirectoryInfo dir = new DirectoryInfo(startFolder);
var fileList = dir.GetFiles("*.*", SearchOption.AllDirectories);

var fileQuery = from file in fileList
                where file.Extension == ".txt"
                orderby file.Name
                select file;

// Uncomment this block to see the full query
// foreach (FileInfo fi in fileQuery)
// {
//    Console.WriteLine(fi.FullName);
// }

var newestFile = (from file in fileQuery
                  orderby file.CreationTime
                  select new { file.FullName, file.CreationTime })
                  .Last();

Console.WriteLine($"\r\nThe newest .txt file is {newestFile.FullName}. Creation time: {newestFile.CreationTime}");

2、如何按扩展名对文件分组

本示例演示如何使用 LINQ 来执行高级分组和对文件或文件夹列表执行排序操作。 它还演示如何使用 Skip 和 Take 方法在控制台窗口中对输出进行分页。

下面的查询演示如何按文件扩展名对指定的目录树的内容进行分组。

string startFolder = """C:\Program Files\dotnet\sdk""";
// Or
// string startFolder = "/usr/local/share/dotnet/sdk";

int trimLength = startFolder.Length;

DirectoryInfo dir = new DirectoryInfo(startFolder);

var fileList = dir.GetFiles("*.*", SearchOption.AllDirectories);

var queryGroupByExt = from file in fileList
                      group file by file.Extension.ToLower() into fileGroup
                      orderby fileGroup.Count(), fileGroup.Key
                      select fileGroup;

// Iterate through the outer collection of groups.
foreach (var filegroup in queryGroupByExt.Take(5))
{
    Console.WriteLine($"Extension: {filegroup.Key}");
    var resultPage = filegroup.Take(20);

    //Execute the resultPage query
    foreach (var f in resultPage)
    {
        Console.WriteLine($"\t{f.FullName.Substring(trimLength)}");
    }
    Console.WriteLine();
}

此程序的输出可能很长,具体取决于本地文件系统的详细信息和 startFolder 的设置。 为了能够查看所有结果,此示例演示如何对结果进行分页。 由于每个组是单独枚举的,因此需要嵌套的 foreach 循环。

3、如何查询一组文件夹中的总字节数

此示例演示如何检索由指定文件夹及其所有子文件夹中的所有文件使用的字节总数。 Sum 方法可将 select 子句中选择的所有项的值相加。 可以修改此查询以检索指定目录树中的最大或最小文件,方法是调用 Min 或 Max 方法,而不是调用 Sum 方法。

string startFolder = """C:\Program Files\dotnet\sdk""";
// Or
// string startFolder = "/usr/local/share/dotnet/sdk";

var fileList = Directory.GetFiles(startFolder, "*.*", SearchOption.AllDirectories);

var fileQuery = from file in fileList
                let fileLen = new FileInfo(file).Length
                where fileLen > 0
                select fileLen;

// Cache the results to avoid multiple trips to the file system.
long[] fileLengths = fileQuery.ToArray();

// Return the size of the largest file
long largestFile = fileLengths.Max();

// Return the total number of bytes in all the files under the specified folder.
long totalBytes = fileLengths.Sum();

Console.WriteLine($"There are {totalBytes} bytes in {fileList.Count()} files under {startFolder}");
Console.WriteLine($"The largest file is {largestFile} bytes.");

此示例扩展了前面的示例以执行以下操作:

  • 如何检索最大文件的大小(以字节为单位)。
  • 如何检索最小文件的大小(以字节为单位)。
  • 如何从指定根文件夹下的一个或多个文件夹检索 FileInfo 对象最大或最小文件。
  • 如何检索序列(如 10 个最大文件)。
  • 如何基于文件大小(以字节为单位)按组对文件进行排序(忽略小于指定大小的文件)。

下面的示例包含五个单独的查询,它们演示如何根据文件大小(以字节为单位)对文件进行查询和分组。 可以修改这些示例,以便使查询基于 FileInfo 对象的其他某个属性。

// Return the FileInfo object for the largest file
// by sorting and selecting from beginning of list
FileInfo longestFile = (from file in fileList
                        let fileInfo = new FileInfo(file)
                        where fileInfo.Length > 0
                        orderby fileInfo.Length descending
                        select fileInfo
                        ).First();

Console.WriteLine($"The largest file under {startFolder} is {longestFile.FullName} with a length of {longestFile.Length} bytes");

//Return the FileInfo of the smallest file
FileInfo smallestFile = (from file in fileList
                         let fileInfo = new FileInfo(file)
                         where fileInfo.Length > 0
                         orderby fileInfo.Length ascending
                         select fileInfo
                        ).First();

Console.WriteLine($"The smallest file under {startFolder} is {smallestFile.FullName} with a length of {smallestFile.Length} bytes");

//Return the FileInfos for the 10 largest files
var queryTenLargest = (from file in fileList
                       let fileInfo = new FileInfo(file)
                       let len = fileInfo.Length
                       orderby len descending
                       select fileInfo
                      ).Take(10);

Console.WriteLine($"The 10 largest files under {startFolder} are:");

foreach (var v in queryTenLargest)
{
    Console.WriteLine($"{v.FullName}: {v.Length} bytes");
}

// Group the files according to their size, leaving out
// files that are less than 200000 bytes.
var querySizeGroups = from file in fileList
                      let fileInfo = new FileInfo(file)
                      let len = fileInfo.Length
                      where len > 0
                      group fileInfo by (len / 100000) into fileGroup
                      where fileGroup.Key >= 2
                      orderby fileGroup.Key descending
                      select fileGroup;

foreach (var filegroup in querySizeGroups)
{
    Console.WriteLine($"{filegroup.Key}00000");
    foreach (var item in filegroup)
    {
        Console.WriteLine($"\t{item.Name}: {item.Length}");
    }
}

若要返回一个或多个完整的 FileInfo 对象,查询必须首先检查数据中的每个对象,然后按其 Length 属性值对它们进行排序。 随后它便可以返回具有最大长度的单个对象或对象序列。 使用 First 返回列表中的第一个元素。 使用 Take 返回前 n 个元素。 指定降序排序顺序可将最小元素置于列表开头。

4、如何在目录树中查询重复文件

有时,可能会有相同名称的文件位于多个文件夹中。 此示例显示如何在指定根文件夹下查询此类重复文件名。 第二个示例显示如何查询大小和上次写入时间都匹配的文件。

string startFolder = """C:\Program Files\dotnet\sdk""";
// Or
// string startFolder = "/usr/local/share/dotnet/sdk";

DirectoryInfo dir = new DirectoryInfo(startFolder);

IEnumerable<FileInfo> fileList = dir.GetFiles("*.*", SearchOption.AllDirectories);

// used in WriteLine to keep the lines shorter
int charsToSkip = startFolder.Length;

// var can be used for convenience with groups.
var queryDupNames = from file in fileList
                    group file.FullName.Substring(charsToSkip) by file.Name into fileGroup
                    where fileGroup.Count() > 1
                    select fileGroup;

foreach (var queryDup in queryDupNames.Take(20))
{
    Console.WriteLine($"Filename = {(queryDup.Key.ToString() == string.Empty ? "[none]" : queryDup.Key.ToString())}");

    foreach (var fileName in queryDup.Take(10))
    {
        Console.WriteLine($"\t{fileName}");
    }   
}

第一个查询使用关键值来确定匹配项。 它会查找名称相同但内容可能不同的文件。 第二个查询使用复合键来匹配 FileInfo 对象的 3 个属性。 此查询更可能找到名称相同且内容相似或相同的文件。

    string startFolder = """C:\Program Files\dotnet\sdk""";
    // Or
    // string startFolder = "/usr/local/share/dotnet/sdk";

    // Make the lines shorter for the console display
    int charsToSkip = startFolder.Length;

    // Take a snapshot of the file system.
    DirectoryInfo dir = new DirectoryInfo(startFolder);
    IEnumerable<FileInfo> fileList = dir.GetFiles("*.*", SearchOption.AllDirectories);

    // Note the use of a compound key. Files that match
    // all three properties belong to the same group.
    // A named type is used to enable the query to be
    // passed to another method. Anonymous types can also be used
    // for composite keys but cannot be passed across method boundaries
    //
    var queryDupFiles = from file in fileList
                        group file.FullName.Substring(charsToSkip) by
                        (Name: file.Name, LastWriteTime: file.LastWriteTime, Length: file.Length )
                        into fileGroup
                        where fileGroup.Count() > 1
                        select fileGroup;

    foreach (var queryDup in queryDupFiles.Take(20))
    {
        Console.WriteLine($"Filename = {(queryDup.Key.ToString() == string.Empty ? "[none]" : queryDup.Key.ToString())}");

        foreach (var fileName in queryDup)
        {
            Console.WriteLine($"\t{fileName}");
        }
    }
}

5、如何查询文件夹中文本文件的内容

此示例演示如何查询指定目录树中的所有文件、打开每个文件并检查其内容。 此类技术可用于对目录树的内容创建索引或反向索引。 此示例中执行的是简单的字符串搜索。 但是,可使用正则表达式执行类型更复杂的模式匹配。

string startFolder = """C:\Program Files\dotnet\sdk""";
// Or
// string startFolder = "/usr/local/share/dotnet/sdk";

DirectoryInfo dir = new DirectoryInfo(startFolder);

var fileList = dir.GetFiles("*.*", SearchOption.AllDirectories);

string searchTerm = "change";

var queryMatchingFiles = from file in fileList
                         where file.Extension == ".txt"
                         let fileText = File.ReadAllText(file.FullName)
                         where fileText.Contains(searchTerm)
                         select file.FullName;

// Execute the query.
Console.WriteLine($"""The term "{searchTerm}" was found in:""");
foreach (string filename in queryMatchingFiles)
{
    Console.WriteLine(filename);
}

标签:startFolder,Console,WriteLine,文件系统,Linq,Length,LINQ,file,var
From: https://blog.csdn.net/llyfe2006/article/details/144172297

相关文章

  • Linq与文件系统:使用 LINQ 查询文件和目录(下)
    许多文件系统操作实质上是查询,因此非常适合使用LINQ方法。这些查询是非破坏性的。它们不会更改原始文件或文件夹的内容。查询不应造成任何副作用。通常,修改源数据的任何代码(包括执行创建/更新/删除操作的查询)应与仅查询数据的代码分开。创建准确表示文件系统的内容并适......
  • NFS网络文件系统
    目录1.NFS介绍2.NFS的主要特点3.NFS的工作原理4.NFS服务端安装配置5.NFS客户端挂载使用6.NFS挂载参数7.NFS挂载实例8.NFS总结本篇文章给大家介绍NFS相关知识,NFS是网络文件系统的缩写,主要功能是通过网络让不同主机系统之间可以共享文件和目录。NFS系统和Windows网络共......
  • 文件系统
    目录文件系统布局文件系统布局文件系统存放在磁盘上。多数磁盘划分为一个或多个分区,每个分区中有一个独立的文件系统。磁盘的0号扇区称为主引导记录(MasterBootRecord,MBR),用来引导计算机。在MBR的结尾是分区表。该表给出了每个分区的起始和结束地址。表中的一个分区被标记为......
  • EXT4文件系统损坏导致的实例无法启动的排查与修复
    原文:https://bbs.huaweicloud.com/blogs/174945现象某现网局点进行POC时,发现某DNcore掉,且一直无法启动。core文件堆栈和dn的pg_log日志中的堆栈信息一致。堆栈中显示checkpoint时进行buffer落盘时导致corelog中报错信息为:couldnotflushdirtydata:Cannotal......
  • Linux文件系统详解(四)
    ......
  • Linux文件系统详解(三)
    ......
  • C# 中的 LINQ:简化数据查询和处理
    C#中的LINQ(LanguageIntegratedQuery)。LINQ是C#中一个非常强大的特性,它允许你以声明式的方式查询数据集合。LINQ不仅简化了数据查询代码,还提供了丰富的查询操作符,使得数据处理更加灵活和高效。以下是一篇关于C#中LINQ的文章。引言LINQ(LanguageIntegratedQuery)是C#......
  • [Linux]文件系统
    文件系统在理解文件系统之前,我们先来看一下关于磁盘方面的内容。磁盘的存储结构盘面:一个磁盘由多个盘片组成,每个盘片都由两面,它的每一个面都可以存储数据,这就是盘面。磁道:在一个盘面上会被划分为一个一个的“圈”,这个“圈”就对应这一个个的磁道。扇区:从盘面中心......
  • 内核审查文件系统变化
    挖矿病毒通常会采用一些技术手段来隐藏自己的行为,比如通过伪装成系统进程、使用内核模块隐藏进程,或者利用其他复杂的技术隐藏其活动。因此,使用常规的命令如fuser或lsof可能无法检测到这些进程,尤其是在它们使用了高级隐藏技术的情况下。为了捕获这些挖矿病毒的创建目录行为,你......
  • 操作系统实验 4 文件系统设计
    一、实验目的通过一个简单文件系统的设计,加深理解文件系统的内部功能及内部实现。二、主要仪器设备、试剂或材料VMware虚拟机三、实验内容为Linux系统设计一个简单的二级文件系统。要求做到以下几点:(1)可以实现下列几条命令。mkdir创建目录rmdir删除目录c......