VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > c#编程 >
  • 异常处理——用C#文件读写错误捕获与恢复

第一部分:C#基础入门
实例7:异常处理——文件读写错误捕获与恢复
实例介绍
文件读写是开发中常见场景,但磁盘满、权限不足、文件不存在等问题随时会导致程序崩溃。异常处理的核心是让程序在错误发生时优雅恢复,而非直接崩溃。本实例通过实现一个健壮的文件读写工具,掌握try-catch-finally、using语句、自定义异常、异常链等核心技巧,理解“捕获-处理-释放资源”的完整流程,让你的程序在复杂环境下更稳定。
需求分析
1.文件读取:读取指定路径的文本文件,处理文件不存在、权限不足等错误;
2.文件写入:写入内容到指定文件,处理vb.net教程C#教程python教程SQL教程access 2010教程磁盘满、被占用等错误;
3.错误恢复:文件不存在时自动创建,内容为空时提示用户;
4.资源安全:确保文件流无论是否发生异常都能正确关闭;
5.自定义异常:处理文件内容不符合预期的场景(如格式错误);
6.友好提示:给用户清晰的错误原因,而非技术栈跟踪信息。
代码实现
csharp

	using System;
	using System.IO;
	using System.Text;
	
	namespace ExceptionHandlingDemo
	{
	// 自定义异常:文件内容不符合预期
	public class InvalidFileContentException : Exception
	{
	public InvalidFileContentException(string message) : base(message) { }
	public InvalidFileContentException(string message, Exception inner) : base(message, inner) { }
	}
	
	class FileHandler
	{
	static void Main(string[] args)
	{
	Console.Write("请输入文件路径(如:test.txt):");
	string filePath = Console.ReadLine()?.Trim() ?? "";
	
	if (string.IsNullOrEmpty(filePath))
	{
	Console.WriteLine("文件路径不能为空!");
	Console.ReadKey();
	return;
	}
	
	try
	{
	// 读取文件
	string content = ReadFile(filePath);
	Console.WriteLine($"文件内容:
{content}");
	
	// 追加内容
	Console.Write("请输入要追加的内容:");
	string appendContent = Console.ReadLine() ?? "";
	WriteFile(filePath, appendContent, append: true);
	Console.WriteLine("内容追加成功!");
	}
	catch (InvalidFileContentException ex)
	{
	Console.WriteLine($"内容错误:{ex.Message}");
	}
	catch (IOException ex)
	{
	Console.WriteLine($"IO错误:{ex.Message}");
	}
	catch (UnauthorizedAccessException ex)
	{
	Console.WriteLine($"权限错误:{ex.Message}");
	}
	catch (Exception ex)
	{
	Console.WriteLine($"未知错误:{ex.Message}");
	}
	finally
	{
	Console.WriteLine("
操作结束(finally块执行,确保资源释放)");
	}
	
	Console.ReadKey();
	}
	
	/// <summary>
	/// 读取文件内容
	/// </summary>
	public static string ReadFile(string filePath)
	{
	if (!File.Exists(filePath))
	{
	// 文件不存在:提示用户并创建空文件
	Console.WriteLine($"文件 {filePath} 不存在,是否创建?(Y/N)");
	if (Console.ReadKey().Key == ConsoleKey.Y)
	{
	WriteFile(filePath, "", append: false);
	Console.WriteLine($"
文件 {filePath} 已创建");
	return "";
	}
	throw new FileNotFoundException($"文件 {filePath} 不存在", filePath);
	}
	
	// using语句:自动释放StreamReader资源(即使发生异常)
	using StreamReader reader = new StreamReader(filePath, Encoding.UTF8);
	string content = reader.ReadToEnd();
	
	// 自定义异常:内容为空时抛出
	if (string.IsNullOrWhiteSpace(content))
	{
	throw new InvalidFileContentException($"文件 {filePath} 内容为空");
	}
	
	return content;
	}
	
	/// <summary>
	/// 写入文件内容
	/// </summary>
	public static void WriteFile(string filePath, string content, bool append = false)
	{
	try
	{
	// using语句:自动关闭FileStream
	using FileStream fs = new FileStream(filePath, append ? FileMode.Append : FileMode.Create, FileAccess.Write);
	using StreamWriter writer = new StreamWriter(fs, Encoding.UTF8);
	writer.Write(content);
	}
	catch (IOException ex)
	{
	// 异常链:包装原始异常,保留上下文
	throw new IOException($"写入文件 {filePath} 失败", ex);
	}
	}
	}
	}

逐行讲解

  1. 自定义异常定义
    csharp
	public class InvalidFileContentException : Exception
	{
	public InvalidFileContentException(string message) : base(message) { }
	public InvalidFileContentException(string message, Exception inner) : base(message, inner) { }
	}

作用:处理业务相关的错误(如文件内容为空),让异常更具语义;
继承Exception:所有自定义异常都应继承自Exception(而非ApplicationException,后者已过时);
InnerException:保留原始异常信息,方便调试(如包装IO异常)。
2. 读取文件的异常处理
csharp

	public static string ReadFile(string filePath)
	{
	if (!File.Exists(filePath))
	{
	// 用户确认后创建文件
	if (Console.ReadKey().Key == ConsoleKey.Y) WriteFile(filePath, "", false);
	else throw new FileNotFoundException(...);
	}
	
	using StreamReader reader = new StreamReader(filePath);
	string content = reader.ReadToEnd();
	
	if (string.IsNullOrWhiteSpace(content)) throw new InvalidFileContentException(...);
	return content;
	}

File.Exists检查:提前判断文件是否存在,提供恢复选项(创建文件);
using语句:自动调用reader.Dispose(),确保文件流关闭(即使抛出异常);
自定义异常抛出:当内容为空时,抛出业务异常,让调用者处理。
3. 写入文件的异常处理
csharp

	public static void WriteFile(string filePath, string content, bool append)
	{
	try
	{
	using FileStream fs = new FileStream(filePath, append ? FileMode.Append : FileMode.Create, FileAccess.Write);
	using StreamWriter writer = new StreamWriter(fs);
	writer.Write(content);
	}
	catch (IOException ex)
	{
	throw new IOException($"写入失败", ex); // 异常链
	}
	}

FileStream参数:FileMode.Append追加内容,FileMode.Create覆盖内容;
异常包装:将原始IO异常包装为更友好的信息,同时保留InnerException(原始异常);
嵌套using:StreamWriter依赖FileStream,嵌套using确保两者都被释放。
4. Main方法中的异常捕获
csharp

	try
	{
	string content = ReadFile(filePath);
	WriteFile(filePath, appendContent);
	}
	catch (InvalidFileContentException ex) { ... }
	catch (IOException ex) { ... }
	catch (Exception ex) { ... }
	finally { ... }

捕获顺序:具体异常优先于通用异常(如先捕获自定义异常,再捕获IO异常,最后捕获Exception);
finally块:无论是否发生异常都会执行(这里用于输出操作结束信息);
友好提示:给用户非技术术语的错误信息(如“权限错误”而非“UnauthorizedAccessException”)。
基础知识拓展

  1. 异常的分类
类型 说明 示例
系统异常 .NET框架定义的异常,继承自SystemException FileNotFoundException、IOException
应用异常 自定义异常,继承自Exception InvalidFileContentException
运行时异常 程序运行时发生的错误 NullReferenceException、IndexOutOfRangeException
  1. try-catch-finally的执行顺序
    1.try块:执行正常逻辑,若发生异常则跳转到对应catch块;
    2.catch块:匹配异常类型,执行处理逻辑;
    3.finally块:无论是否发生异常,都会执行(用于释放资源);
    注意:若try块中有return,finally块仍会在return前执行。
  2. using语句的本质
    using (var resource = new DisposableResource()) { ... }
    等价于:
    csharp
	var resource = new DisposableResource();
	try
	{
	...
	}
	finally
	{
	resource.Dispose(); // 即使发生异常也会执行
	}

适用场景:所有实现IDisposable接口的对象(如文件流、数据库连接);
优势:简化资源管理,避免遗漏Dispose调用。
4. 异常处理最佳实践
1.不要吞异常:避免catch (Exception) { }(不处理异常且不抛出);
2.具体异常优先:先捕获具体异常(如FileNotFoundException),再捕获通用异常;
3.提供有用信息:异常消息应说明“什么错、哪里错、怎么解决”;
4.保留异常链:用InnerException传递原始异常信息;
5.释放资源:用using或finally确保资源释放(如文件流、网络连接)。
扩展思考
1.日志记录:用Serilog或log4net记录异常到文件/数据库,方便排查问题;
2.重试机制:文件被占用时,重试3次后再抛出异常(用Task.Delay实现);
3.异步文件操作:用async/await处理异步IO,异常捕获方式不变(try-catch包裹await调用);
4.跨平台路径:用Path.Combine处理路径(如Path.Combine(Environment.CurrentDirectory, "test.txt"));
5.验证文件格式:读取CSV文件时,验证每行的列数,抛出InvalidFileFormatException。
总结
异常处理的核心是让程序更健壮,而非掩盖错误。正确的异常处理应做到:
1.捕获并处理:对能恢复的错误(如文件不存在)提供解决方案;
2.传递并记录:对无法处理的错误(如权限不足),传递给上层并记录日志;
3.释放资源:确保无论是否发生异常,资源都能被正确释放;
4.友好提示:给用户清晰的错误信息,帮助用户解决问题。
通过本实例,你已掌握文件读写中的异常处理技巧,这些技巧可迁移到数据库操作、网络请求等场景,让你的程序在复杂环境下稳定运行。

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


相关教程