404 Not Found

404 Not Found


nginx

实战:LINQ与文件综合

学生成绩分析器

将学生数据序列化为JSON文件,再反序列化后用LINQ进行多维度统计分析:平均分、前三名、及格人数、按等级分组。

需求

示例

CSHARP
using System;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Collections.Generic;

public class Student
{
    public string Name { get; set; }
    public int Score { get; set; }
}

class Program
{
    static void Main()
    {
        var students = new List<Student>
        {
            new Student { Name = "张三", Score = 92 },
            new Student { Name = "李四", Score = 45 },
            new Student { Name = "王五", Score = 78 },
            new Student { Name = "赵六", Score = 88 },
            new Student { Name = "钱七", Score = 55 },
            new Student { Name = "孙八", Score = 95 },
            new Student { Name = "周九", Score = 33 },
            new Student { Name = "吴十", Score = 71 }
        };

        string tempDir = Path.GetTempPath();
        string filePath = Path.Combine(tempDir, "students.json");

        var options = new JsonSerializerOptions { WriteIndented = true };
        string json = JsonSerializer.Serialize(students, options);
        File.WriteAllText(filePath, json);
        Console.WriteLine("已写入: " + filePath);

        string readJson = File.ReadAllText(filePath);
        var loaded = JsonSerializer.Deserialize<List<Student>>(readJson);

        double average = loaded.Average(s => s.Score);
        Console.WriteLine($"平均分: {average:F1}");

        var top3 = loaded.OrderByDescending(s => s.Score).Take(3);
        Console.WriteLine("前三名:");
        foreach (var s in top3)
        {
            Console.WriteLine($"  {s.Name} - {s.Score}");
        }

        int passCount = loaded.Count(s => s.Score >= 60);
        Console.WriteLine($"及格人数: {passCount}");

        var grouped = loaded.GroupBy(s => s.Score >= 90 ? "优秀"
            : s.Score >= 60 ? "及格" : "不及格");
        Console.WriteLine("等级分组:");
        foreach (var group in grouped)
        {
            Console.WriteLine($"  {group.Key}: {string.Join(", ", group.Select(s => s.Name))}");
        }

        File.Delete(filePath);
    }
}
▶ 试一试
TEXT
已写入: /tmp/students.json
平均分: 69.6
前三名:
  孙八 - 95
  张三 - 92
  赵六 - 88
及格人数: 5
等级分组:
  优秀: 张三, 孙八
  不及格: 李四, 钱七, 周九
  及格: 王五, 赵六, 吴十

简易日志分析器

读取文本日志文件,解析每一行,用LINQ统计错误/警告数量、查找最高频错误、按日期范围过滤。

需求

示例

CSHARP
using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        string tempDir = Path.GetTempPath();
        string logPath = Path.Combine(tempDir, "app.log");

        var lines = new List<string>
        {
            "[2025-01-10] [INFO] 系统启动",
            "[2025-01-10] [WARN] 内存使用率80%",
            "[2025-01-11] [ERROR] 数据库连接失败",
            "[2025-01-11] [ERROR] 磁盘已满",
            "[2025-01-12] [INFO] 用户登录",
            "[2025-01-12] [ERROR] 数据库连接失败",
            "[2025-01-13] [WARN] CPU使用率90%",
            "[2025-01-13] [ERROR] 网络超时",
            "[2025-01-14] [INFO] 定时任务完成",
            "[2025-01-14] [ERROR] 数据库连接失败"
        };
        File.WriteAllLines(logPath, lines);

        var logEntries = File.ReadAllLines(logPath)
            .Select(line =>
            {
                var parts = line.Split(']');
                return new
                {
                    Date = parts[0].TrimStart('[').Trim(),
                    Level = parts[1].TrimStart('[').Trim(),
                    Message = parts[2].Trim()
                };
            })
            .ToList();

        var levelCounts = logEntries
            .GroupBy(e => e.Level)
            .Select(g => new { Level = g.Key, Count = g.Count() })
            .OrderByDescending(x => x.Count);
        Console.WriteLine("级别统计:");
        foreach (var item in levelCounts)
        {
            Console.WriteLine($"  {item.Level}: {item.Count}条");
        }

        var topError = logEntries
            .Where(e => e.Level == "ERROR")
            .GroupBy(e => e.Message)
            .OrderByDescending(g => g.Count())
            .First();
        Console.WriteLine($"最高频错误: {topError.Key} ({topError.Count()}次)");

        var filtered = logEntries
            .Where(e => string.Compare(e.Date, "2025-01-11") >= 0
                     && string.Compare(e.Date, "2025-01-13") <= 0)
            .ToList();
        Console.WriteLine("1月11日-13日日志:");
        foreach (var entry in filtered)
        {
            Console.WriteLine($"  [{entry.Date}] [{entry.Level}] {entry.Message}");
        }

        File.Delete(logPath);
    }
}
▶ 试一试
TEXT
级别统计:
  ERROR: 5条
  INFO: 3条
  WARN: 2条
最高频错误: 数据库连接失败 (3次)
1月11日-13日日志:
  [2025-01-11] [ERROR] 数据库连接失败
  [2025-01-11] [ERROR] 磁盘已满
  [2025-01-12] [INFO] 用户登录
  [2025-01-12] [ERROR] 数据库连接失败
  [2025-01-13] [WARN] CPU使用率90%
  [2025-01-13] [ERROR] 网络超时

文件批量重命名工具

列出目录中的文件,用LINQ按扩展名过滤,再批量添加前缀或后缀。

需求

示例

CSHARP
using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        string workDir = Path.Combine(Path.GetTempPath(), "rename_demo");
        Directory.CreateDirectory(workDir);

        var demoFiles = new[] { "photo1.jpg", "photo2.jpg", "doc.txt", "notes.txt", "data.csv" };
        foreach (var f in demoFiles)
        {
            File.WriteAllText(Path.Combine(workDir, f), "demo");
        }
        Console.WriteLine("原始文件:");
        foreach (var f in Directory.GetFiles(workDir))
        {
            Console.WriteLine("  " + Path.GetFileName(f));
        }

        string targetExt = ".txt";
        string prefix = "backup_";

        var filesToRename = Directory.GetFiles(workDir)
            .Where(f => Path.GetExtension(f).Equals(targetExt, StringComparison.OrdinalIgnoreCase))
            .ToList();

        Console.WriteLine($"\n筛选扩展名 {targetExt}:");
        foreach (var f in filesToRename)
        {
            string dir = Path.GetDirectoryName(f);
            string nameNoExt = Path.GetFileNameWithoutExtension(f);
            string newName = prefix + nameNoExt + targetExt;
            string newPath = Path.Combine(dir, newName);
            Console.WriteLine($"  {Path.GetFileName(f)} -> {newName}");
            File.Move(f, newPath);
        }

        Console.WriteLine("\n重命名后:");
        foreach (var f in Directory.GetFiles(workDir))
        {
            Console.WriteLine("  " + Path.GetFileName(f));
        }

        Directory.Delete(workDir, true);
    }
}
▶ 试一试
TEXT
原始文件:
  photo1.jpg
  photo2.jpg
  doc.txt
  notes.txt
  data.csv

筛选扩展名 .txt:
  doc.txt -> backup_doc.txt
  notes.txt -> backup_notes.txt

重命名后:
  photo1.jpg
  photo2.jpg
  backup_doc.txt
  backup_notes.txt
  data.csv

❓ 常见问题

Q JSON反序列化时属性名不匹配怎么办?
A 使用 [JsonPropertyName] 特性标注映射名称,或自定义 JsonSerializerOptions 的 PropertyNamingPolicy。
Q LINQ的GroupBy分组顺序是固定的吗?
A 不是,GroupBy不保证分组顺序,需用OrderBy排序后再遍历。
Q File.Move重命名时目标文件已存在会怎样?
A 会抛出IOException,应先检查目标路径是否存在或使用File.Replace。
Q 读取大日志文件用ReadAllLines合适吗?
A 不合适,ReadAllLines会一次性加载全部内容到内存,大文件应使用File.ReadLines进行懒加载逐行读取。

📖 小节

📝 作业

  1. 扩展学生成绩分析器,增加按分数段(0-59/60-79/80-89/90-100)统计人数并输出柱状图(用*表示)
  2. 为日志分析器添加功能:统计每天的ERROR数量,输出连续出现ERROR最多的日期区间
  3. 改造文件重命名工具,支持通过命令行参数指定目录路径、扩展名过滤条件和前缀,并添加--dry-run模式只显示预览不实际执行
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏