using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.IO; using System.Text.RegularExpressions; using System.Runtime.Serialization.Formatters.Binary; // 知识点: // TreeView控件的应用:添加、修改、删除节点 // 得到当前节点、父节点的值 // 响应节点选择事件 // 节点存储数据 namespace Ch0602_学生成绩_二进制文件_ { public partial class FrmGrade : Form { public FrmGrade() { InitializeComponent(); } private void btnAddSC_Click(object sender, EventArgs e) { if (cboType.SelectedIndex == 0) { // 添加学校节点,并指定该节点为当前节点 if (txtNameSC.Text.Length > 0) { TreeNode node = tvSC.Nodes.Add(txtNameSC.Text); tvSC.SelectedNode = node; } else MessageBox.Show("请指定学校的名称"); } else { if (tvSC.SelectedNode == null || tvSC.SelectedNode.Level >= 1) MessageBox.Show("先选择学校,然后再创建班级节点"); else { // 添加班级节点,并展开学校节点 if (txtNameSC.Text.Length > 0) { tvSC.SelectedNode.Nodes.Add(txtNameSC.Text); tvSC.SelectedNode.Expand(); } else MessageBox.Show("请指定班级的名称"); } } } private void btnAddStud_Click(object sender, EventArgs e) { if (tvSC.SelectedNode == null || tvSC.SelectedNode.Level != 1) { MessageBox.Show("请指定班级"); return; } string sname = tvSC.SelectedNode.Parent.Text; string cname = tvSC.SelectedNode.Text; Student stud = new Student(sname, cname); stud.No = txtNo.Text; stud.Name = txtName.Text; stud.Sex = cboSex.Text; stud.Birth = DateTime.Parse(dtpBirth.Text); stud.Grade = int.Parse(txtGrade.Text); stud.Addr = txtAddr.Text; TreeNode node = tvSC.SelectedNode.Nodes.Add(stud.No); // 给添加的节点绑定数据 node.Tag = stud; // 展开班级节点 tvSC.SelectedNode.Expand(); } private void tvSC_AfterSelect(object sender, TreeViewEventArgs e) { // 显示当前节点内容 if (tvSC.SelectedNode != null && tvSC.SelectedNode.Level == 2 && tvSC.SelectedNode.Tag != null) { Student stud = (Student)tvSC.SelectedNode.Tag; lboStudent.Items.Add(stud.ToString()); txtNo.Text = stud.No; txtName.Text = stud.Name; cboSex.Text = stud.Sex; dtpBirth.Text = stud.Birth.ToString(); txtGrade.Text = stud.Grade.ToString(); txtAddr.Text = stud.Addr; } } private void tvSC_AfterSelect(object sender, TreeViewEventArgs e) { // 显示当前节点内容 if (tvSC.SelectedNode != null && tvSC.SelectedNode.Level == 2 && tvSC.SelectedNode.Tag != null) { Student stud = (Student)tvSC.SelectedNode.Tag; lboStudent.Items.Add(stud.ToString()); txtNo.Text = stud.No; txtName.Text = stud.Name; cboSex.Text = stud.Sex; dtpBirth.Text = stud.Birth.ToString(); txtGrade.Text = stud.Grade.ToString(); txtAddr.Text = stud.Addr; } } private void cboType_SelectedIndexChanged(object sender, EventArgs e) { txtNameSC.Clear(); } private void btnModStud_Click(object sender, EventArgs e) { if (tvSC.SelectedNode == null || tvSC.SelectedNode.Level != 2) { MessageBox.Show("请指定学生"); return; } string sname = tvSC.SelectedNode.Parent.Parent.Text; string cname = tvSC.SelectedNode.Parent.Text; Student stud = new Student(sname, cname); stud.No = txtNo.Text; stud.Name = txtName.Text; stud.Sex = cboSex.Text; stud.Birth = DateTime.Parse(dtpBirth.Text); stud.Grade = int.Parse(txtGrade.Text); stud.Addr = txtAddr.Text; // 修改节点信息 tvSC.SelectedNode.Text = stud.No; // 修改节点的绑定数据 tvSC.SelectedNode.Tag = stud; } private void btnDelStud_Click(object sender, EventArgs e) { // 删除节点数据 tvSC.SelectedNode.Remove(); } // 读文本文件,生成树结构 private void miFileRead_Click(object sender, EventArgs e) { // 显示打开文件对话框 OpenFileDialog dlgOpen = new OpenFileDialog(); if (dlgOpen.ShowDialog() != DialogResult.OK) return; // 以指定文件和编码格式打开文件,准备读 StreamReader sr = new StreamReader(dlgOpen.FileName, Encoding.Default); tvSC.Nodes.Clear(); string pattern = @"\s*,\s*|\s+"; // “\s”表示空格,“\s*”表示0个或多个空格,“\s+”表示1个或多个空格 string sname0 = "", cname0 = ""; // 读取一行文本 string line; string[] fields; while ((line = sr.ReadLine()) != null) { //fields = line.Split(' ', '\t'); fields = Regex.Split(line, pattern); string sname = fields[0]; string cname = fields[1]; Student stud = new Student(sname, cname); stud.No = fields[2]; stud.Name = fields[3]; stud.Sex = fields[4]; stud.Birth = Convert.ToDateTime(fields[5]); stud.Grade = int.Parse(fields[6]); stud.Addr = fields[7]; // 如果学校名改变了,添加学校节点 if (sname != sname0) { tvSC.SelectedNode = tvSC.Nodes.Add(sname); sname0 = sname; } // 如果班级名改变了,添加班级节点 if (cname != cname0) { // 调整当前节点 if (tvSC.SelectedNode.Level == 1) tvSC.SelectedNode = tvSC.SelectedNode.Parent; tvSC.SelectedNode = tvSC.SelectedNode.Nodes.Add(cname); cname0 = cname; } // 添加学生节点 TreeNode node = tvSC.SelectedNode.Nodes.Add(stud.No); node.Tag = stud; } // 关闭文件 sr.Close(); } // 遍历树结构,写文本文件 private void miFileWrite_Click(object sender, EventArgs e) { // 显示保存文件对话框 SaveFileDialog dlgSave = new SaveFileDialog(); if (dlgSave.ShowDialog() != DialogResult.OK) return; // 指定文件和编码格式打开指定文件准备写 StreamWriter sw = new StreamWriter(dlgSave.FileName, false, Encoding.Default); // 遍历树结构,写文本文件 WriteTxtFile(sw, tvSC.Nodes); // 关闭文件 sw.Close(); } // 用递归遍历一棵树所有节点 private void WriteTxtFile(StreamWriter sw, TreeNodeCollection nodes) { foreach (TreeNode node in nodes) { if (node.Level == 2) { Student stud = node.Tag as Student; string line = string.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5:yyyy-MM-dd}\t{6}\t{7}", stud.Sname, stud.Cname, stud.No, stud.Name, stud.Sex, stud.Birth, stud.Grade, stud.Addr); sw.WriteLine(line); } if (node.Nodes.Count > 0) WriteTxtFile(sw, node.Nodes); } } private void miFileReadBin_Click(object sender, EventArgs e) { OpenFileDialog dlgOpen = new OpenFileDialog(); if (dlgOpen.ShowDialog() != DialogResult.OK) return; FileStream fs = new FileStream(dlgOpen.FileName, FileMode.Open, FileAccess.Read); tvSC.Nodes.Clear(); // 建立一个读流的类br BinaryReader br = new BinaryReader(fs); // 初始化变量 string sname0 = "", cname0 = ""; // 文件指针指向文件头 br.BaseStream.Seek(0, SeekOrigin.Begin); // 循环读,直到文件指针指向文件尾 while (br.BaseStream.Position < br.BaseStream.Length) { // 按字段读出每个学生的记录 Student stud = new Student(); stud.Sname = br.ReadString(); stud.Cname = br.ReadString(); stud.No = br.ReadString(); stud.Name = br.ReadString(); stud.Sex = br.ReadString(); stud.Birth = Convert.ToDateTime(br.ReadString()); stud.Grade = br.ReadInt32(); stud.Addr = br.ReadString(); // 添加到树形节点 // 如果学校名改变了,添加学校节点 if (stud.Sname != sname0) { tvSC.SelectedNode = tvSC.Nodes.Add(stud.Sname); sname0 = stud.Sname; } // 如果班级名改变了,添加班级节点 if (stud.Cname != cname0) { // 调整当前节点 if (tvSC.SelectedNode.Level == 1) tvSC.SelectedNode = tvSC.SelectedNode.Parent; tvSC.SelectedNode = tvSC.SelectedNode.Nodes.Add(stud.Cname); cname0 = stud.Cname; } // 添加学生节点 TreeNode node = tvSC.SelectedNode.Nodes.Add(stud.No); node.Tag = stud; } br.Close(); fs.Close(); } private void miFileWriteBin_Click(object sender, EventArgs e) { // 显示保存文件对话框 SaveFileDialog dlgSave = new SaveFileDialog(); if (dlgSave.ShowDialog() != DialogResult.OK) return; // 建立一个写文件流fs FileStream fs = new FileStream(dlgSave.FileName, FileMode.Create, FileAccess.Write); // 建立一个写流的类bw BinaryWriter bw = new BinaryWriter(fs); // 遍历树结构,写文本文件 WriteBinFile(bw, tvSC.Nodes); // 关闭写流类和文件流 bw.Close(); fs.Close(); } // 用递归遍历一棵树所有节点 private void WriteBinFile(BinaryWriter bw, TreeNodeCollection nodes) { foreach (TreeNode node in nodes) { if (node.Level == 2) { Student stud = node.Tag as Student; bw.Write(stud.Sname); bw.Write(stud.Cname); bw.Write(stud.No); bw.Write(stud.Name); bw.Write(stud.Sex); bw.Write(stud.Birth.ToString("yyyy-MM-dd")); bw.Write(stud.Grade); bw.Write(stud.Addr); } if (node.Nodes.Count > 0) WriteBinFile(bw, node.Nodes); } } private void miFileReadBin2_Click(object sender, EventArgs e) { OpenFileDialog dlgOpen = new OpenFileDialog(); if (dlgOpen.ShowDialog() != DialogResult.OK) return; FileStream fs = new FileStream(dlgOpen.FileName, FileMode.Open, FileAccess.Read); BinaryReader br = new BinaryReader(fs); tvSC.Nodes.Clear(); // 初始化变量 string sname0 = "", cname0 = ""; // 文件指针指向文件头 fs.Seek(0, SeekOrigin.Begin); // 循环读,直到文件指针指向文件尾 while (fs.Position < fs.Length) { // 按字段读出每个学生的记录 int length = br.ReadInt32(); byte[] buffer = new byte[length]; buffer = br.ReadBytes(length); Student stud = (Student)BytesToObject(buffer); // 添加到树形节点 // 如果学校名改变了,添加学校节点 if (stud.Sname != sname0) { tvSC.SelectedNode = tvSC.Nodes.Add(stud.Sname); sname0 = stud.Sname; } // 如果班级名改变了,添加班级节点 if (stud.Cname != cname0) { // 调整当前节点 if (tvSC.SelectedNode.Level == 1) tvSC.SelectedNode = tvSC.SelectedNode.Parent; tvSC.SelectedNode = tvSC.SelectedNode.Nodes.Add(stud.Cname); cname0 = stud.Cname; } // 添加学生节点 TreeNode node = tvSC.SelectedNode.Nodes.Add(stud.No); node.Tag = stud; } br.Close(); fs.Close(); } private void miFileWriteBin2_Click(object sender, EventArgs e) { // 显示保存文件对话框 SaveFileDialog dlgSave = new SaveFileDialog(); if (dlgSave.ShowDialog() != DialogResult.OK) return; // 建立一个写文件流fs FileStream fs = new FileStream(dlgSave.FileName, FileMode.Create, FileAccess.Write); BinaryWriter bw = new BinaryWriter(fs); // 遍历树结构,写文本文件 WriteBinFile2(bw, tvSC.Nodes); // 关闭写流类和文件流 bw.Close(); fs.Close(); } private void WriteBinFile2(BinaryWriter bw, TreeNodeCollection nodes) { foreach (TreeNode node in nodes) { if (node.Level == 2) { Student stud = node.Tag as Student; byte[] buffer = ObjectToBytes(stud); bw.Write(buffer.Length); bw.Write(buffer); } if (node.Nodes.Count > 0) WriteBinFile2(bw, node.Nodes); } } // 对象序列化为字节数组 public static byte[] ObjectToBytes(Object obj) { MemoryStream ms = new MemoryStream(); byte[] bytes = null; try { // 序列化 BinaryFormatter formatter = new BinaryFormatter(); formatter.Serialize(ms, obj); bytes = ms.ToArray(); } catch (Exception e) { throw new Exception(e.ToString()); } finally { ms.Close(); } return bytes; } // 字节数组反序列化为对象 public static Object BytesToObject(byte[] bytes) { MemoryStream ms = new MemoryStream(bytes); Object obj = new Object(); try { // 反序列化 ms.Position = 0; BinaryFormatter formatter = new BinaryFormatter(); obj = formatter.Deserialize(ms); } catch (Exception e) { throw new Exception(e.ToString()); } finally { ms.Close(); } return obj; } private void miClear_Click(object sender, EventArgs e) { tvSC.Nodes.Clear(); } } }
下面是类的定义。
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Ch0602_学生成绩_二进制文件_ { [Serializable] public class Student { public string Sname { get; set; } public string Cname { get; set; } public string No { get; set; } public string Name { get; set; } public string Sex { get; set; } public DateTime Birth { get; set; } public int Grade { get; set; } public string Addr { get; set; } public Student() { } public Student(string sname, string cname) { Sname = sname; Cname = cname; } public new string ToString() { return string.Format("{0}:{1},{2},{3:yyyy-MM-dd},{4},{5}", No, Name, Sex, Birth, Grade, Addr); } } }