VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > c#编程 >
  • 文件读写——用C#编写日志文件生成与分析

第一部分:C#基础入门
实例12:文件读写——用C#编写日志文件生成与分析
实例介绍
日志文件是程序运行的“黑匣子”,能记录关键操作、错误信息和系统状态,是调试问题、监控性能、排查故障的核心依据。C#提供了丰富的文件读写API,从简单的File静态类到灵活的流操作(StreamWriter/StreamReader),能满足不同场景的日志需求。
本实例通过实现日志生成器(按日期分割文件、自动管vb.net教程C#教程python教程SQL教程access 2010教程理目录)和日志分析器(统计级别、搜索关键词),带你掌握C#文件读写的底层逻辑,理解流操作的资源管理,学会编写可靠的日志系统。
需求分析
1.日志生成:
1.支持3种日志级别:Info(普通信息)、Warn(警告)、Error(错误);
2.日志格式:[时间戳][级别] 内容(如[2025-12-11 14:30:25.123][Error] 数据库连接失败);
3.按日期分割文件(如2025-12-11.log),自动创建日志目录;
4.处理异常:文件被占用、权限不足时不崩溃,输出错误提示。
2.日志分析:
1.统计日志文件中不同级别的记录数量;
2.搜索包含特定关键词的日志行;
3.支持读取任意日志文件路径。
3.测试验证:生成多种日志,分析结果是否符合预期。</think_never_used_51bce0c785ca2f68081bfa7d91973934>#</think_never_used_51bce0c785ca2f68081bfa7d91973934>#</think_never_used_51bce0c785ca2f68081bfa7d91973934># 《C#实例驱动开发指南:100个实用案例从入门到精通》
第一部分:C#基础入门
实例12:文件读写——用C#编写日志文件生成与分析
实例介绍
日志文件是程序运行的“黑匣子”,能记录关键操作、错误信息和系统状态,是调试问题、监控性能、排查故障的核心依据。C#提供了丰富的文件读写API,从简单的File静态类到灵活的流操作(StreamWriter/StreamReader),能满足不同场景的日志需求。
本实例通过实现日志生成器(按日期分割文件、自动管理目录)和日志分析器(统计级别、搜索关键词),带你掌握C#文件读写的底层逻辑,理解流操作的资源管理,学会编写可靠的日志系统。
需求分析
1.日志生成:
1.支持3种日志级别:Info(普通信息)、Warn(警告)、Error(错误);
2.日志格式:[时间戳][级别] 内容(如[2025-12-11 14:30:25.123][Error] 数据库连接失败);
3.按日期分割文件(如2025-12-11.log),自动创建日志目录;
4.处理异常:文件被占用、权限不足时不崩溃,输出错误提示。
2.日志分析:
1.统计日志文件中不同级别的记录数量;
2.搜索包含特定关键词的日志行;
3.支持读取任意日志文件路径。
3.测试验证:生成多种日志,分析结果是否符合预期。
代码实现
csharp

	using System;
	using System.Collections.Generic;
	using System.IO;
	using System.Linq;
	
	namespace LogFileDemo
	{
	// ==================== 1. 日志级别枚举 ====================
	public enum LogLevel
	{
	Info,
	Warn,
	Error
	}
	
	// ==================== 2. 日志生成器 ====================
	public class LogGenerator
	{
	private readonly string _logDirectory;
	
	public LogGenerator(string logDirectory)
	{
	_logDirectory = logDirectory;
	if (!Directory.Exists(_logDirectory))
	{
	Directory.CreateDirectory(_logDirectory);
	Console.WriteLine($"日志目录已创建:{_logDirectory}");
	}
	}
	
	public void WriteLog(LogLevel level, string message)
	{
	try
	{
	string fileName = $"{DateTime.Now:yyyy-MM-dd}.log";
	string logPath = Path.Combine(_logDirectory, fileName);
	
	using (StreamWriter writer = new StreamWriter(logPath, append: true, System.Text.Encoding.UTF8))
	{
	string logLine = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}][{level}] {message}";
	writer.WriteLine(logLine);
	Console.WriteLine($"日志写入成功:{logLine}");
	}
	}
	catch (IOException ex)
	{
	Console.WriteLine($"日志写入失败(文件被占用/磁盘满):{ex.Message}");
	}
	catch (UnauthorizedAccessException ex)
	{
	Console.WriteLine($"日志写入失败(权限不足):{ex.Message}");
	}
	catch (Exception ex)
	{
	Console.WriteLine($"日志写入失败:{ex.Message}");
	}
	}
	}
	
	// ==================== 3. 日志分析器 ====================
	public class LogAnalyzer
	{
	public Dictionary<LogLevel, int> CountLogLevels(string logPath)
	{
	var levelCount = new Dictionary<LogLevel, int>
	{
	{ LogLevel.Info, 0 },
	{ LogLevel.Warn, 0 },
	{ LogLevel.Error, 0 }
	};
	
	try
	{
	if (!File.Exists(logPath))
	{
	Console.WriteLine($"日志文件不存在:{logPath}");
	return levelCount;
	}
	
	using (StreamReader reader = new StreamReader(logPath))
	{
	string line;
	while ((line = reader.ReadLine()) != null)
	{
	if (line.Contains("[Info]")) levelCount[LogLevel.Info]++;
	else if (line.Contains("[Warn]")) levelCount[LogLevel.Warn]++;
	else if (line.Contains("[Error]")) levelCount[LogLevel.Error]++;
	}
	}
	}
	catch (Exception ex)
	{
	Console.WriteLine($"日志分析失败:{ex.Message}");
	}
	
	return levelCount;
	}
	
	public List<string> SearchLog(string logPath, string keyword)
	{
	var result = new List<string>();
	try
	{
	if (!File.Exists(logPath)) return result;
	
	using (StreamReader reader = new StreamReader(logPath))
	{
	string line;
	while ((line = reader.ReadLine()) != null)
	{
	if (line.Contains(keyword, StringComparison.OrdinalIgnoreCase))
	{
	result.Add(line);
	}
	}
	}
	}
	catch (Exception ex)
	{
	Console.WriteLine($"日志搜索失败:{ex.Message}");
	}
	return result;
	}
	}
	
	// ==================== 4. 测试程序 ====================
	class Program
	{
	static void Main(string[] args)
	{
	// 生成日志
	string logDir = Path.Combine(Environment.CurrentDirectory, "Logs");
	var logGenerator = new LogGenerator(logDir);
	logGenerator.WriteLog(LogLevel.Info, "程序启动成功");
	logGenerator.WriteLog(LogLevel.Warn, "内存使用率达75%");
	logGenerator.WriteLog(LogLevel.Error, "数据库连接超时");
	logGenerator.WriteLog(LogLevel.Info, "用户admin登录");
	
	// 分析日志
	var logAnalyzer = new LogAnalyzer();
	string todayLog = Path.Combine(logDir, $"{DateTime.Now:yyyy-MM-dd}.log");
	
	Console.WriteLine("
=== 日志级别统计 ===");
	var countResult = logAnalyzer.CountLogLevels(todayLog);
	foreach (var kvp in countResult)
	{
	Console.WriteLine($"{kvp.Key}:{kvp.Value}条");
	}
	
	Console.WriteLine("
=== 搜索关键词'数据库'的日志 ===");
	var searchResult = logAnalyzer.SearchLog(todayLog, "数据库");
	foreach (var line in searchResult)
	{
	Console.WriteLine(line);
	}
	}
	}
	}

逐行讲解

  1. 日志级别枚举
    csharp
    public enum LogLevel { Info, Warn, Error }
    用枚举替代字符串常量,避免拼写错误,提升类型安全性。
  2. 日志生成器
    构造函数:
    csharp
	public LogGenerator(string logDirectory)
	{
	_logDirectory = logDirectory;
	if (!Directory.Exists(_logDirectory)) Directory.CreateDirectory(_logDirectory);
	}

接收日志目录路径,检查目录是否存在,不存在则自动创建(支持多级目录)。
WriteLog方法:
csharp

	public void WriteLog(LogLevel level, string message)
	{
	try
	{
	string fileName = $"{DateTime.Now:yyyy-MM-dd}.log"; // 按日期命名
	string logPath = Path.Combine(_logDirectory, fileName); // 安全组合路径
	
	using (StreamWriter writer = new StreamWriter(logPath, append: true, Encoding.UTF8))
	{
	string logLine = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}][{level}] {message}";
	writer.WriteLine(logLine);
	}
	}
	catch (IOException ex) { ... } // 处理文件占用等IO错误
	}

Path.Combine:自动处理跨平台路径分隔符(Windows用,Linux用/);
StreamWriter:追加模式写入,UTF8编码确保字符正确;
using语句:自动释放文件资源,避免句柄泄漏;
异常处理:捕获具体异常类型,精准定位问题。
3. 日志分析器
CountLogLevels方法:
csharp

	public Dictionary<LogLevel, int> CountLogLevels(string logPath)
	{
	var levelCount = new Dictionary<LogLevel, int> { ... };
	try
	{
	using (StreamReader reader = new StreamReader(logPath))
	{
	string line;
	while ((line = reader.ReadLine()) != null)
	{
	if (line.Contains("[Info]")) levelCount[LogLevel.Info]++;
	// ...其他级别判断
	}
	}
	}
	catch (Exception ex) { ... }
	return levelCount;
	}

StreamReader.ReadLine:逐行读取日志,避免一次性加载大文件导致内存溢出;
Contains方法:简单判断日志级别,实际项目可改用正则表达式提升准确性。
SearchLog方法:
csharp

	public List<string> SearchLog(string logPath, string keyword)
	{
	var result = new List<string>();
	using (StreamReader reader = new StreamReader(logPath))
	{
	string line;
	while ((line = reader.ReadLine()) != null)
	{
	if (line.Contains(keyword, StringComparison.OrdinalIgnoreCase))
	{
	result.Add(line);
	}
	}
	}
	return result;
	}

StringComparison.OrdinalIgnoreCase:忽略大小写搜索,提升用户体验。
4. 测试程序
csharp

	static void Main(string[] args)
	{
	string logDir = Path.Combine(Environment.CurrentDirectory, "Logs"); // 程序运行目录下创建Logs文件夹
	var logGenerator = new LogGenerator(logDir);
	// ...生成日志
	var logAnalyzer = new LogAnalyzer();
	// ...分析日志
	}

Environment.CurrentDirectory:获取程序当前运行目录,避免硬编码绝对路径;
测试生成不同级别日志,再统计和搜索,验证功能正确性。
基础知识拓展

  1. C#文件读写核心类对比
    | 类名 | 作用 | 适用场景 |
    | ---- | ---- | ---- |
    | File | 静态类,封装常用操作(如AppendAllText) | 简单一次性写入(小文件) |
    | StreamWriter | 文本写入流,支持追加、编码设置 | 频繁写入(如日志) |
    | StreamReader | 文本读取流,逐行读取 | 大文件分析 |
    | FileStream | 字节流,支持任意文件类型 | 二进制文件操作(如图片) |

性能建议:频繁写入日志时用StreamWriter,而非File.AppendAllText(后者每次打开/关闭文件,性能低)。
2. 路径处理最佳实践
避免硬编码:用Environment.CurrentDirectory/AppDomain.CurrentDomain.BaseDirectory获取程序路径;
安全组合:Path.Combine自动处理分隔符,Path.GetFileName提取文件名;
跨平台兼容:Path类方法在Windows/Linux上均有效。
3. 日志优化技巧
异步写入:用StreamWriter.WriteAsync避免阻塞主线程:
csharp

await writer.WriteLineAsync(logLine); // 方法需标记async

滚动日志:按文件大小分割(如超过10MB创建新文件);
结构化日志:用JSON格式存储(如{"Time":"2025-12-11","Level":"Error","Message":"数据库错误"}),便于后续解析。
扩展思考
1.如何实现按大小分割日志?
每次写入前检查文件大小,超过阈值则创建新文件(如2025-12-11_01.log);
2.如何异步生成日志?
用Task.Run包裹写入逻辑,或直接用异步流操作;
3.第三方日志库对比:
NLog/Serilog:支持滚动日志、多目标输出(文件/数据库/控制台),无需手写文件操作;
4.日志归档:如何自动压缩7天前的日志文件?
用ZipFile.CreateFromDirectory压缩旧日志,然后删除原文件。
总结
本实例通过日志生成与分析,覆盖了C#文件读写的核心用法:路径处理、流操作、异常处理。日志系统是项目基础组件,手写实现能帮助理解底层逻辑,但实际项目推荐使用成熟库(如Serilog)提升效率。掌握文件读写是后端开发必备技能,需注意性能优化和异常处理,确保系统稳定。

本站原创,转载请注明出处:https://www.xin3721.com/ArticlecSharp/c49414.html


相关教程