您的当前位置:首页正文

文件读写

2024-03-06 来源:意榕旅游网
文件读写

简介

本讲涉及的内容有:读写文本文件、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的Sort()方法中,会自动调用Student的CompareTo()方法比较两个元素的大小;②在List的Sort()方法中定义排序的委托;③在VS2008中List的Sort()方法中定义排序委托的另一种形式。

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,希望能够显示该文件的记录,并可以对该文件进行插入、修改和删除操作。

Visual C#程序设计教程 刘先省 27.00

构建一个基本的XML文档需要记住关键的四点: 所有元素必须有开始/结束标签;

所有元素必须正确的嵌套(不允许交迭元素); 所有特征值必须加引号;

每一个文档都必须有一个唯一的第一元素和根节点

2.2 实现要点

整个XML文件是一个XmlDocument对象,该对象由多个不同级别的XmlNode构成,一些父节点XmlNode由多个子节点XmlNode构成,即构成了XmlNodeList。一个节点也叫一个元素,一个元素内可以有多个属性,通过GetAttribute()方法,可以得到这些属性的值。一个节点可以通过InnerText或InnerXml属性得到节点的值。

如节点bookstore的InnerText和InnerXml的值分别为:

Visual C#程序设计教程刘先省27.00

Visual C#程序设计教程刘先省27.00

如节点book节点的InnerText和InnerXml的值分别为:

Visual C#程序设计教程刘先省27.00

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)); } } }

因篇幅问题不能全部显示,请点此查看更多更全内容