C#CSV数据格式读写 +Settings 用户配置文件读写 +try-catch 异常捕获与常见异常类型
一、CSV文件基础认知(必背知识点)
1. 什么是CSV文件
CSV全称逗号分隔值文件,是一种纯文本轻量化表格文件,无需依赖Excel软件即可打开、编辑、读写,常用于存储小型结构化数据、日志数据、简单数据表。
2. CSV核心格式规则
① 整体结构:表头行 + 数据行
② 列与列之间使用英文逗号 , 分隔
③ 每一行代表一条独立的数据信息,第一行为表头,后续为内容数据
④ 纯文本存储,体积小、读写速度快、兼容性极强
3. 必备引用命名空间
所有文件、文件夹、文本流操作必须引入以下命名空间,否则代码报错:
using System.IO; //文件、文件夹、文件流核心操作
using System.Text; //字符串拼接(StringBuilder)
using System.Windows.Forms;
二、项目结构说明
本案例分为两大核心模块:
1、CSVAPI工具类:封装CSV文件创建、表头写入、数据追加、文件读取核心方法,解耦业务代码
2、Form1窗体类:调用工具类,实现一键写入数据、一键解析读取数据功能
第一部分:CSVAPI 工具类完整代码详解
1、工具类命名空间与类定义
namespace _3csv数据格式
{
//CSV文件读写工具类,封装所有CSV操作方法
public class CSVAPI
{
2、写入数据方法 SaveData(核心重点)
功能作用:自动检测/创建存储文件夹、自动创建CSV文件、首次写入表头、后续追加数据,不覆盖原有数据
/// <summary>
/// 向CSV文件写入人员数据(自动创建目录、自动生成表头、追加写入)
/// </summary>
/// <param name="name">姓名</param>
/// <param name="age">年龄</param>
/// <param name="sex">性别</param>
public static void SaveData(string name, string age, string sex)
{
//=====================第一步:处理文件夹路径=====================
//获取程序运行根目录(Debug文件夹路径)
string dirPath = Directory.GetCurrentDirectory() + @"\data";
//判断data文件夹是否存在,不存在则手动创建
if (!Directory.Exists(dirPath))
{
Directory.CreateDirectory(dirPath);
}
代码细节解析:
Directory.GetCurrentDirectory():获取程序运行的Debug目录,动态适配路径,无需写死绝对路径
Directory.Exists():判断文件夹是否存在,避免重复创建
Directory.CreateDirectory():不存在则自动创建data文件夹,防止路径不存在报错
//=====================第二步:处理文件路径=====================
string filePath = dirPath + @"\1.csv";
//判断CSV文件是否存在,不存在则创建文件并写入表头
if (!File.Exists(filePath))
{
//创建文件流:指定文件路径、创建模式、写入权限
FileStream fs = new FileStream(filePath,FileMode.Create,FileAccess.Write);
//创建文本写入流,指定默认编码,解决中文乱码问题
StreamWriter sw = new StreamWriter(fs,Encoding.Default);
//拼接CSV表头:姓名、年龄、性别
StringBuilder sb = new StringBuilder();
sb.Append("姓名").Append(",").Append("年龄").Append(",").Append("性别");
//将表头写入文件,自动换行
sw.WriteLine(sb);
//手动关闭流、释放系统资源(旧版本写法)
sw.Close();
fs.Close();
sw.Dispose();
fs.Dispose();
}
核心细节解析:
FileMode.Create:文件不存在则创建,存在则覆盖(仅首次创建表头使用)
Encoding.Default:适配系统中文编码,彻底解决CSV中文乱码
StringBuilder:高效拼接字符串,优于字符串直接相加,性能更高
必须手动关闭释放流资源,避免文件被程序占用、无法二次编辑
//=====================第三步:追加写入数据内容=====================
//using语法:自动释放流资源,无需手动Close、Dispose
//第二个参数true:开启【追加模式】,保留旧数据,新增数据换行写入
using (StreamWriter sw = new StreamWriter(filePath,true,Encoding.Default))
{
//拼接当前传入的人员数据
StringBuilder sb = new StringBuilder();
sb.Append(name).Append(",").Append(age).Append(",").Append(sex);
//写入一行数据
sw.WriteLine(sb);
}
}
关键必考知识点:
StreamWriter(filePath,true):true=追加模式,保留原有数据
StreamWriter(filePath, false):false=覆盖模式,清空旧数据重写
using语句包裹流对象:代码执行完毕后自动释放资源,杜绝内存泄漏,是开发标准写法
3、读取数据方法 ReadData
功能作用:读取完整CSV文件所有文本内容,以字符串形式返回
/// <summary>
/// 读取CSV文件全部文本数据
/// </summary>
/// <returns>CSV完整文本字符串</returns>
public static string ReadData()
{
//1、拼接文件夹路径,自动补全目录
string dirPath = Directory.GetCurrentDirectory() + @"\data";
if (!Directory.Exists(dirPath))
{
Directory.CreateDirectory(dirPath);
}
//2、拼接完整文件路径
string filePath = dirPath + @"\1.csv";
//3、创建读取流,读取文件内容
StreamReader sr = new StreamReader(filePath,Encoding.Default);
//读取文件所有内容,一次性全部读取
string ss = sr.ReadToEnd();
//4、释放资源
sr.Close();
sr.Dispose();
//返回完整CSV文本
return ss;
}
}
}
核心方法解析:
ReadToEnd():读取文件全部文本,包含所有表头、数据、换行符
读取后的字符串保留原始CSV格式:换行\n、逗号, 分隔符,为后续分割解析做铺垫
第二部分:窗体调用代码完整详解
1、窗体初始化代码
namespace _3csv数据格式
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
2、按钮1:写入CSV测试数据
功能:点击按钮,自动向CSV写入一条模拟人员数据
private void button1_Click(object sender, EventArgs e)
{
//调用工具类静态方法,写入固定模拟数据
CSVAPI.SaveData("梅西","20","男");
}
3、按钮2:读取并解析CSV数据(核心难点)
功能:读取完整CSV文本,通过分割算法,剔除表头、空行,解析出每一个单元格数据
private void button2_Click(object sender, EventArgs e)
{
//1、调用工具类读取全部CSV文本
string data = CSVAPI.ReadData();
//2、第一次分割:按【换行符\n】分割,将文本拆分为【每一行数据】
string[] arr = data.Split('\n');
//3、创建新数组,剔除表头和最后空行
//arr.Length-2:减去第一行表头、最后一行空数据
string[] newArr = new string[arr.Length-2];
//4、循环筛选有效数据行
for (int i = 0; i < arr.Length; i++)
{
//i>0:跳过第0行(表头)
//i<arr.Length-1:跳过最后一行空行
if (i>0&&i<arr.Length-1)
{
newArr[i - 1] = arr[i];
}
}
筛选逻辑详解:
CSV原始读取内容包含:表头行、数据行、末尾空行,必须过滤无效行,否则解析报错
通过下标判断,只保留中间真实的业务数据行
//5、遍历所有有效数据行
foreach (string item in newArr)
{
//6、第二次分割:按【逗号,】分割,将一行数据拆分为单个单元格数据
string[] arr1 = item.Split(',');
//7、遍历每个单元格数据,弹窗展示
foreach (var item1 in arr1)
{
MessageBox.Show(item1);
}
}
}
}
}
第三部分:CSV解析完整执行流程
步骤1:写入流程
判断文件夹 → 无则创建 → 判断文件 → 无则创建并写入表头 → 追加写入数据
步骤2:读取解析流程
读取完整文本 → 按换行分行 → 过滤表头、空行 → 按逗号分列 → 遍历展示单个数据
第四部分:核心知识点汇总
1、文件夹操作核心类 Directory
Directory:文件夹操作(判断、创建目录)
GetCurrentDirectory():获取程序运行根目录
Exists():判断文件夹是否存在
CreateDirectory():创建文件夹
2、文件操作核心类 File、文件流
File.Exists():判断文件是否存在
FileStream:底层文件操作流,负责创建、打开文件
StreamWriter:文本写入,true=追加模式,false=覆盖模式
StreamReader:文本读取,ReadToEnd读取全部内容
StringBuilder:高效拼接字符串,适合批量拼接数据
3、追加与覆盖区别
new StreamWriter(path, true):追加写入,保留旧数据
new StreamWriter(path, false):覆盖写入,清空旧数据
4、CSV双层分割算法(必考)
第一层 Split('\n'):按行分割
第二层 Split(','):按列分割
第五部分:易错点总结
1、未判断文件夹是否存在,直接写入会报路径不存在异常
2、未写入表头,CSV文件无字段,表格结构错乱
3、未开启追加模式,每次写入都会覆盖历史数据
4、未指定编码Encoding.Default,中文乱码
5、解析数据未过滤表头和空行,读取到无效空数据
6、不释放文件流资源,导致文件被占用,无法修改、删除
Settings 用户配置文件读写
一、Settings 配置核心知识点
1. 什么是Settings配置
Settings 是 .NET 框架原生自带的用户配置类,专门用于快速保存软件用户参数、临时配置、个人偏好设置。
对比 INI、CSV:无需手动创建文件、无需读写流、无需DLL调用,一行代码即可读写保存。
2. Settings 两种作用域
1、Application 应用程序级:全局只读、所有用户共用、无法代码修改保存
2、User 用户级(本案例使用):可读写、每个用户独立配置、支持代码动态Save保存
3. 存储位置
自动保存到系统用户目录,无需手动管理文件路径,由 .NET 框架自动托管。
4. 支持的数据类型
字符串、整型、布尔、浮点、颜色、字体、路径等常用所有数据类型
二、前期创建步骤(考试/作业必写步骤)
1、右键项目 → 属性 → 设置
2、点击“创建设置文件”
3、添加三个配置项:
|
名称 |
类型 |
范围 |
默认值 |
|---|---|---|---|
|
name |
string |
User |
张三 |
|
age |
int |
User |
20 |
|
sex |
bool |
User |
False |
4、保存后自动生成配置节点与Settings类,无需手动手写实体
三、自动生成 App.config 配置文件详解
该文件由VS自动生成,负责记录所有用户配置的默认值、配置节点类型
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<!-- 配置节点声明:固定模板,声明用户配置组 -->
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="_4setting读写.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
</startup>
<!-- 用户配置区域:所有可读写配置都写在这里 -->
<userSettings>
<_4setting读写.Properties.Settings>
<setting name="name" serializeAs="String">
<value>张三</value>
</setting>
<setting name="age" serializeAs="String">
<value>20</value>
</setting>
<setting name="sex" serializeAs="String">
<value>False</value>
</setting>
</_4setting读写.Properties.Settings>
</userSettings>
</configuration>
字段解析:
name:配置字段名,对应代码属性
serializeAs="String":以字符串形式序列化存储
value:配置默认初始值
四、窗体业务代码逐段精细拆解
1、命名空间与窗体初始化
namespace _4setting读写
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
2、写入/修改配置按钮(Button1)
核心功能:获取全局配置对象 → 重新赋值 → 持久化保存到本地
/// <summary>
/// 写入/修改用户配置
/// </summary>
private void button1_Click(object sender, EventArgs e)
{
//1、获取系统默认的全局配置单例对象
//Settings.Default 是固定写法,拿到配置实例
Settings set = Settings.Default;
//2、给自定义配置字段重新赋值(覆盖默认值)
set.name = "李四";
set.age = 40;
set.sex = true;
//3、关键方法:Save() 持久化保存到本地配置文件
//不调用Save,修改只在内存生效,重启程序失效
set.Save();
}
重点必考细节:
1、Settings.Default:全局唯一单例对象,固定获取方式
2、赋值后必须调用 Save(),否则数据只存在内存中,重启丢失
3、直接赋值即可自动覆盖原有配置,无需判断、无需新建文件
3、读取配置按钮(Button2)
核心功能:读取本地已保存的配置数据,弹窗展示
/// <summary>
/// 读取用户配置
/// </summary>
private void button2_Click(object sender, EventArgs e)
{
//1、获取配置对象
Settings set = Settings.Default;
//2、直接读取配置字段值,弹窗展示
MessageBox.Show(set.name);
}
}
}
读取逻辑:优先读取用户修改保存后的最新值,无修改则读取默认值。
五、完整执行流程
1、手动在项目设置中创建 name、age、sex 三个User类型配置
2、程序自动在App.config生成默认配置数据
3、点击写入按钮:修改内存中配置 → Save保存到本地文件
4、点击读取按钮:加载本地配置 → 获取最新数据展示
5、重启程序数据不丢失,实现永久保存
六、Settings 优缺点总结
优点
1、.NET原生支持,无需引用第三方库、无需Dll导入、无需文件流操作
2、强类型存储(自动识别int、bool、string),不会类型错乱
3、代码极简,只需要 取值、赋值、Save三步
4、自动管理文件,无需关心路径
5、重启程序数据保留,持久化效果好
缺点
1、只适合存储少量配置,不适合大量数据(对比CSV)
2、User级别仅对当前电脑用户生效
七、高频易错点(必背)
1、忘记点击【设置】创建配置文件,直接写代码报错
2、配置范围选错成Application,无法修改、无法Save保存
3、赋值后不调用Save(),数据内存生效、重启丢失
4、字段名大小写不一致,读取不到数据、报错
5、数据类型不匹配(例如int存字符串)编译报错
八、三种本地存储对比总结
INI:依靠系统DLL、手动封装、适合通用配置、跨平台兼容差
CSV:文件流读写、适合大量表格数据、手动解析分割
Settings:原生最强、最简代码、强类型、适合软件小型配置
try-catch 异常捕获与常见异常类型
一、异常基础核心知识点
1. 什么是异常
程序运行中出现的非语法错误,代码语法没问题,但运行时逻辑出错,导致程序直接崩溃退出。
异常不处理:程序闪退、终止运行;
异常捕获处理:程序不崩溃,友好提示错误,可重试继续运行。
2. try-catch 标准结构
try
{
//有可能出错、会抛异常的风险代码
}
catch (具体异常类型 ex)
{
//捕获对应异常,处理错误逻辑
}
catch (Exception ex)
{
//捕获所有未知、剩余所有异常(兜底)
}
3. 异常捕获优先级规则(必考)
1、先写具体异常,最后写Exception基类异常
2、顺序不能颠倒,否则具体异常永远不会执行
3、Exception是所有异常的父类,可以捕获所有异常
4. 代码中常用五大异常(必背)
1. FormatException:数据格式错误(字符串转数字格式非法)
2. OverflowException:数值超出数据类型范围(数字太大/太小)
3. DivideByZeroException:除数为0异常
4. IndexOutOfRangeException:数组/集合索引越界
5. NullReferenceException:空引用异常(对象为null调用属性/下标)
6. Exception:所有异常的基类,万能兜底捕获
二、案例一:数字输入多异常精准捕获(核心案例)
完整解析代码 + 逐行详解
namespace _5try.@catch
{
internal static class Program
{
/// <summary>
/// 应用程序的主入口点。
///
[STAThread]
static void Main()
{
inputNum: //跳转标签,用于出错重试
try
{
//风险代码:用户输入、类型转换、数学运算都可能报错
Console.WriteLine("请输入合法数字");
string s = Console.ReadLine();
//1、输入字母符号 → 报格式异常
//2、输入数字超出int范围 → 报溢出异常
int num = int.Parse(s);
//计算10的num次方
double sum = Math.Pow(10, num);
Console.WriteLine(sum);
}
//精准捕获:格式错误异常(输入非数字)
catch (FormatException ex)
{
//ex.Message:获取系统原生异常描述信息
Console.WriteLine(ex.Message);
//出错后跳转回输入,重新输入
goto inputNum;
}
//精准捕获:数值超出范围异常
catch (OverflowException ex)
{
Console.WriteLine("输入数字超出范围");
goto inputNum;
}
//兜底捕获:所有未知异常
catch (Exception ex)
{
Console.WriteLine("无法预料的异常");
//throw ex; //抛出异常,让程序崩溃(不推荐)
}
逐段逻辑详解
1. goto标签 inputNum
作用:异常出错后,不退出程序,跳转回顶部重新输入,实现错误重试效果
2. FormatException 场景
用户输入:abc、#$%、中文、空内容
int.Parse 无法转换,触发格式异常
ex.Message:打印系统自带的详细错误原因
3. OverflowException 场景
用户输入超大数字,超出 int 类型取值范围
int范围:-2147483648 ~ 2147483647
数字过大/过小,触发数值溢出异常
4. Exception 兜底捕获
捕获前面没有匹配到的所有未知异常,保证程序绝对不崩溃
throw ex; 作用:手动抛出异常,让程序终止(调试用,项目中一般不写)
三、案例二:数组索引越界异常捕获
//数组索引越界异常案例
i1:
//接收用户输入索引
int a = int.Parse(Console.ReadLine());
try
{
//定义固定长度数组(下标0、1、2、3)
int[] ss = new int[] { 1, 2, 3, 4, };
//根据用户输入下标取值,超出0-3直接越界
Console.WriteLine(ss[a]);
}
//精准捕获:索引越界异常
catch (IndexOutOfRangeException ex)
{
Console.WriteLine(ex.Message + "++++++++");
//出错重试
goto i1;
}
//兜底捕获所有其他异常
catch (Exception)
{
//throw空抛:向上抛出异常,程序崩溃
throw;
}
案例解析
数组长度为4,合法下标:0、1、2、3
用户输入 4、5、-1 等非法下标 → 触发 IndexOutOfRangeException
goto i1:越界后重新输入,程序不闪退
throw; 空抛:不传递异常对象,直接向上抛出错误,终止程序
四、案例三:空引用异常演示(NullReferenceException)
//空引用异常案例
int[] arr = null; //数组变量为空,没有指向任何对象
Console.WriteLine(arr[0]); //空对象调用下标,直接报错
异常原因
变量只是声明,没有实例化、没有开辟内存,值为null
对null对象进行读取、调用、取值,触发空引用异常(项目最常见报错)
五、程序入口窗体启动代码
//窗体程序固定启动模板
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
六、throw 抛异常核心知识点
1. throw ex;
抛出当前捕获的异常信息,保留完整异常堆栈信息
2. throw;
空抛出,向上传递异常,保留原始异常信息
3. throw new Exception("自定义错误");
手动创建自定义异常,自定义错误提示文本
注意:不写throw,异常被吃掉,程序正常运行,无报错崩溃
七、try-catch 开发规范(必考面试点)
1、能精准捕获就精准捕获,不要全部直接用Exception
2、具体异常在前,Exception兜底在后,顺序绝对不能乱
3、业务异常必须处理,避免程序闪退崩溃
4、可以配合goto实现错误重试机制
5、ex.Message 获取系统标准错误信息,方便排错
八、所有异常场景汇总复盘
FormatException:字符串转数字、格式非法
OverflowException:数值超出类型存储范围
IndexOutOfRangeException:数组、集合下标越界
NullReferenceException:空对象调用方法/属性/下标
DivideByZeroException:除数为0
Exception:所有异常的基类,万能兜底
更多推荐


所有评论(0)