简介
本讲涉及的内容有:读写文本文件、INI文件、XML文件、二进制文件等四种常用文件格式。还有:定义/使用结构类型的变量、对象列表;自定义列表对象的排序方法;建立/使用自己的类库;定义/使用非托管的Dll;对象序列化等。
1 读写文本文件
1.1 功能要求
假设有如下文本文件Test_in.txt,希望读出该文件内容,然后计算总人数和平均成绩,并按分数排序(介绍三种实现排序的方式),将排序后的结束输出列文本框中,同时写到文件Test_out.txt中。
学号 姓名 课程名 分数 95001, 张三, 数学, 95.2 95001, 张三, 物理, 87.0 95002, 李四, 数学, 78.5 95002, 李四, 英语, 65.0 95003, 王五, 英语, 75.0 95003, 王五, 数学, a45 95003, 王五, 物理, -45
1.2 实现要点
首先定义了一个结构对象Student,使用StreamReader对象读文本文件,每次从文件中读一行,使用Regex.Split()方法将读入行的数据分解成一个个字符串,存入到一个字符串数组sFields中,然后对字符串进行用户需要的处理。
// 定义结构
public struct Student : IComparable public string Sno; public string Sname; public string Cname; public double Grade; // 定义一个构造函数 public Student(string sno, string sname, string cname, double grade) { Sno = sno; Sname = sname; Cname = cname; Grade = grade; } #region IComparable 成员 // 实现升排列:前者比后者大,返回1,否则返回-1 public int CompareTo(Student student) { if (this.Grade > student.Grade) return 1; else if (this.Grade < student.Grade) return -1; else return 0; } #endregion } private void btnReadTxt_Click(object sender, EventArgs e) { // 指定文件和编码格式 StreamReader sr = new StreamReader(@\"..\\..\\Test_in.txt\", Encoding.Default); // 下面的模式表示逗号分隔符或空格分隔符 // “\\s”表示空格,“\\s*”表示0个或多个空格,“\\s+”表示1个或多个空格 string pattern = @\"\\s*,\\s*|\\s+\"; string sLine; // 源数据行 string[] sFields; // 分解后的字符串数组 int nGradeCount = 0; double dGradeSum = 0.0; // 读取一行文本 while ((sLine = sr.ReadLine()) != null) { // 将源数据行写入到文本框中 txtContents.AppendText(sLine + \"\\n\"); // 使用逗号或空格作为分隔符分解行的各个字段 sFields = Regex.Split(sLine, pattern); // 如果是标题行,不进行计算和排序 if (sFields[0].Trim() == \"学号\") continue; // 将字符串数组中的值读入到一个结构对象链表中 if (sFields.Length >= 4) { Student student = new Student(); student.Sno = sFields[0].Trim(); student.Sname = sFields[1].Trim(); student.Cname = sFields[2].Trim(); //student.Grade = MyConvert.ToDouble(sFields[3], 0.0); student.Grade = MyConvert.ToDouble(sFields[3], 0.0, 0.0, 100.0); nGradeCount++; dGradeSum += student.Grade; _listStudent.Add(student); } } dGradeSum /= nGradeCount; // 将数值转换为字符串 txtContents.AppendText(string.Format(\"人数:{0},平均分:{1}\\n\", nGradeCount, dGradeSum)); } 在将字符串数据转换成数值型数据时,考虑到异常数据的处理,本程序采用了一个用户自定义的类库实现,在自定义类库lwhCsLib.MyConvert中,实现了两个静态方法ToDouble(),可以为异常数据指定默认值,而且还可以指定有效数值的范围。 public static double ToDouble(string value, double defValue) { try { return Convert.ToDouble(value); } catch (Exception) { return (defValue); } } public static double ToDouble(string value, double defValue, double minValue, double maxValue) { try { double valTemp = Convert.ToDouble(value); if (valTemp < minValue || valTemp > maxValue) valTemp = defValue; return valTemp; } catch (Exception) { return (defValue); } } 在将读入的成绩输出之前,按成绩排序后再输出,本文介绍了三种排序方式:①在数据类Student中实现ICompare接口的方法CompareTo(),在List private void btnWriteTxt_Click(object sender, EventArgs e) { //== 输出到文本框前按成绩升序排序 // 排序方法1:在数据类中实现接口IComparable,实现升序 _listStudent.Sort(); // 输出到文本框 txtContents.AppendText(\"\\n----- 排序后输出 -----\\n\"); foreach (Student student in _listStudent) { // 格式化输出字符串 string sLine = string.Format(\"{0}, {1}, {2}, {3}\\n\", student.Sno, student.Sname, student.Cname, student.Grade); // 输出到文本框 txtContents.AppendText(sLine); } //== 输出到文件中前按成绩降序排序 // 方法2:在Sort()中定义委托,实现降序 _listStudent.Sort(delegate(Student x, Student y) { if (x.Grade > y.Grade) return -1; else if (x.Grade < y.Grade) return 1; else return 0; }); // 方法3:在VS2008中,可以如下定义Sort()中的委托,实现降序 _listStudent.Sort((x, y) => Convert.ToInt32(y.Grade - x.Grade)); // 指定输出文件和编码格式:指定false表示采用重写文件方式 StreamWriter sw = new StreamWriter(@\"..\\..\\Test_out.txt\", false, Encoding.Default); foreach (Student student in _listStudent) { // 格式化输出字符串 string sLine = string.Format(\"{0}, {1}, {2}, {3}\\n\", student.Sno, student.Sname, student.Cname, student.Grade); // 输出到文件 sw.WriteLine(sLine); } sw.Close(); } 2 读写INI文件 2.1 功能要求 假设有如下INI文件Config.ini,希望能从该文件读出指定节指定字段的内容,并可向指定节指定字段写内容。 [Login] ServerName=161.92.95.5 UserName=cnh05051 [DeskTop] PicStyle=1 PicNum=10 2.2 实现要点 由于.Net类库不直接支持读写INI文件,我们可以调用Windows API的功能,即可以调用非托管的DLL,如下: // 定义非托管的DLL方法 [DllImport(\"kernel32\")] private static extern long WritePrivateProfileString( string section, string key, string val, string filePath); [DllImport(\"kernel32\")] private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath); 使用上面定义的二个方法,分别可以读指定文件指定节指定字段的值或写值,如下: private void btnReadIni_Click(object sender, EventArgs e) { StringBuilder str = new StringBuilder(255); string sFileName = txtFileIni.Text; string sSection = txtSectionRead.Text; string sKey = txtKeyRead.Text; // 从Ini文件读指定字段的值,如果指定字段没有值,则返回用户指定的默认值 int i = GetPrivateProfileString(sSection, sKey, \"默认值\", str, 255, sFileName); // 显示读取的数值 txtValueRead.Text = str.ToString(); } private void btnWriteIni_Click(object sender, EventArgs e) { string sFileName = txtFileIni.Text; string sSection = txtSectionWrite.Text; string sKey = txtKeyWrite.Text; string sValue = txtValueWrite.Text; // 向Ini文件写指定字段的值 WritePrivateProfileString(sSection, sKey, sValue, sFileName ) ; } 3 读写XML文件 3.1 功能要求 假设有如下XML文件BookStore.XML,希望能够显示该文件的记录,并可以对该文件进行插入、修改和删除操作。 构建一个基本的XML文档需要记住关键的四点: 所有元素必须有开始/结束标签; 所有元素必须正确的嵌套(不允许交迭元素); 所有特征值必须加引号; 每一个文档都必须有一个唯一的第一元素和根节点 2.2 实现要点 整个XML文件是一个XmlDocument对象,该对象由多个不同级别的XmlNode构成,一些父节点XmlNode由多个子节点XmlNode构成,即构成了XmlNodeList。一个节点也叫一个元素,一个元素内可以有多个属性,通过GetAttribute()方法,可以得到这些属性的值。一个节点可以通过InnerText或InnerXml属性得到节点的值。 如节点bookstore的InnerText和InnerXml的值分别为: Visual C#程序设计教程刘先省27.00 如节点book节点的InnerText和InnerXml的值分别为: Visual C#程序设计教程刘先省27.00 显示Xml文件中的内容,实现如下: // 显示文件内容 private void btnShow_Click(object sender, EventArgs e) { // 创建XmlDDocument对象,并装入xml文件 XmlDocument xmlDoc = new XmlDocument(); xmlDoc.Load(@\"..\\..\\BookStore.xml\"); // 得到根节点bookstore XmlNode xn = xmlDoc.SelectSingleNode(\"bookstore\"); // 得到根节点的所有子节点 XmlNodeList xnl = xn.ChildNodes; // 对所有子节点进行操作 txtContents.Clear(); foreach (XmlNode xn1 in xnl) { // 将节点转换为元素,便于得到节点的属性值 XmlElement xe = (XmlElement)xn1; // 得到Type和ISBN两个属性的属性值 txtContents.AppendText(string.Format(\"Type: {0}\", xe.GetAttribute(\"Type\"))); txtContents.AppendText(string.Format(\, xe.GetAttribute(\"ISBN\"))); // 得到Book节点的所有子节点 XmlNodeList xnl0 = xe.ChildNodes; // 得到所有子节点的值(通过InnerText属性得到) foreach (XmlNode xn2 in xnl0) { // 显示子节点点文本 txtContents.AppendText(string.Format(\"{0}\\n\", xn2.InnerText)); } } } 因篇幅问题不能全部显示,请点此查看更多更全内容