Hi, its me again, I promise this should be quick and simple because I have an idea of what needs to be done.

I'm working on my form (if you saw my other post its basicly a grade book with 5 forms). Is there any simple way to write the student name with the scores to a text file.

From reading my book it looks simple, but I am unsure how to redo my array since it will only be pulling data from a text file and then any new data will be written into the text file.

Here is the starting code I have gotten so far:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace maint_student_scores
{
    public class StudentDB
    {

        private const string dir = @"C:\C#.NET\Files\";
		private const string path = dir + "StudentScores.txt";

		public static List<Student> GetStudentScores()
		{
			// if the directory doesn't exist, create it
			if (!Directory.Exists(dir))
				Directory.CreateDirectory(dir);

			// create the object for the input stream for a text file
			StreamReader textIn = 
				new StreamReader(
				new FileStream(path, FileMode.OpenOrCreate, FileAccess.Read));

			// create the list
			List<Student> students = new List<Student>();

			// read the data from the file and store it in the list
			while (textIn.Peek() != -1)
			{
				string row = textIn.ReadLine();
				string[] columns = row.Split('|');
				Student studentlist = new Student();
                studentlist.Name = columns[0];
                studentlist.Score = columns[1];
                students.Add(studentlist);
			}

			// close the input stream for the text file
			textIn.Close();

			return students;
		}

		public static void SaveStudents(List<Student> studentlist)
		{
			// create the output stream for a text file that exists
			StreamWriter textOut = 
				new StreamWriter(
				new FileStream(path, FileMode.Create, FileAccess.Write));

			// write each product
			foreach (Student s in studentlist)
			{
				textOut.Write(s.Name + "|");
				textOut.WriteLine(s.Score);
			}

			// close the output stream for the text file
			textOut.Close();
	   }
	}
}

I'm going to guess my above code is correct for the most part, because it looks like it would work.
Since I'm working with multi-forms, would I then set all the List I have in my different forms to null?
I.E.: public List<Student> studentList = null;
that is taken from the first form that is loaded the one that will list all the student names.

I think I'm going in the right direction with this?

Recommended Answers

All 8 Replies

Why not use XML serialization of the class?

Mock up student & grade classes:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.IO;

namespace daniweb
{
  public class Student
  {
    private string _firstName;
    private string _lastName;
    private List<Grade> _grades;

    public string FirstName
    {
      get { return _firstName; }
      set { _firstName = value; }
    }
    public string LastName
    {
      get { return _lastName; }
      set { _lastName = value; }
    }
    public List<Grade> Grades
    {
      get { return _grades; }
      set
      {
        if (value == null)
          return;
        _grades = value;
      }
    }

    public Student()
    {
      this.FirstName = string.Empty;
      this.LastName = string.Empty;
      this.Grades = new List<Grade>();
    }
    public Student(string FirstName)
      : this()
    {
      this.FirstName = FirstName;
    }
    public Student(string FirstName, string LastName)
      : this(FirstName)
    {
      this.LastName = LastName;
    }
    public static void SaveToFile(string FileName, Student student)
    {
      if (student == null)
        throw new ArgumentNullException("student");
      SaveToFile(FileName, new Student[] { student }.ToList());
    }
    public static void SaveToFile(string FileName, Student[] students)
    {
      if (students == null)
        throw new ArgumentNullException("students");
      SaveToFile(FileName, students.ToList());
    }
    public static void SaveToFile(string FileName, List<Student> students)
    {
      if (students == null)
        throw new ArgumentNullException("students");
      using (FileStream fs = new FileStream(FileName, FileMode.Create))
      {
        XmlSerializer ser = new XmlSerializer(typeof(List<Student>));
        ser.Serialize(fs, students);
      }
    }
    public static List<Student> LoadFromFile(string FileName)
    {
      XmlSerializer ser = new XmlSerializer(typeof(List<Student>));
      using (FileStream fs = new FileStream(FileName, FileMode.Open))
      {
        return (List<Student>)ser.Deserialize(fs);
      }
    }
  }
  public class Grade
  {
    private string _course;
    private decimal _score;

    public string Course
    {
      get { return _course; }
      set { _course = value; }
    }
    public decimal Score
    {
      get { return _score; }
      set { _score = value; }
    }

    public Grade()
    {
      this.Course = string.Empty;
    }
    public Grade(string Course)
      : this()
    {
      this.Course = Course;
    }
    public Grade(string Course, decimal Score)
      : this(Course)
    {
      this.Score = Score;
    }
  }
}

Calling it:

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;

namespace daniweb
{
  public partial class frmStudent : Form
  {
    public frmStudent()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      const string gradeBookFileName = @"C:\gradebook.xml";
      #region persist the scores
      {
        List<Student> lst = new List<Student>();

        Student s = new Student();
        s.FirstName = "Scott";
        s.LastName = "Knake";
        s.Grades.Add(new Grade("Math", 1));
        s.Grades.Add(new Grade("Math", 2));
        s.Grades.Add(new Grade("Math", 3));
        lst.Add(s);

        Student.SaveToFile(gradeBookFileName, lst);
      }
      #endregion

      #region load the scores
      {
        List<Student> lst = Student.LoadFromFile(gradeBookFileName);
        MessageBox.Show(lst.Count.ToString());
      }
      #endregion
    }
  }
}

File:

<?xml version="1.0"?>
<ArrayOfStudent xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Student>
    <FirstName>Scott</FirstName>
    <LastName>Knake</LastName>
    <Grades>
      <Grade>
        <Course>Math</Course>
        <Score>1</Score>
      </Grade>
      <Grade>
        <Course>Math</Course>
        <Score>2</Score>
      </Grade>
      <Grade>
        <Course>Math</Course>
        <Score>3</Score>
      </Grade>
    </Grades>
  </Student>
</ArrayOfStudent>

I'd love my projects to be that simple :(, but it requires us to write to a text file (which is lame I know). But from looking over the code it looks like its kind the same idea, or is it different for writing to a text file and calling the method?

Thank you for the quick reply on this.

Just change the file extension. It is a text file with XML in it. You could use .exe, .txt, .dat, or whatever you want

Ok I'll give this a whirl in the morning, thanks for the help. I'll check and see if I can do it as an XML file, because I know that makes it a bit simpler and more functional to add on to stuff.

Just a quick final question, is there going to be any issues if the data is from an array that is passed between different forms, like there an add student, update student, update score? I'm going to guess this wouldn't matter, I would use the same calling functions to store\update the data to the text\xml file.

You are correct -- it won't matter. Passing around the references just gives you visibility to the in-memory data in various parts of the application but won't affect the serialization.

You are correct -- it won't matter. Passing around the references just gives you visibility to the in-memory data in various parts of the application but won't affect the serialization.

Alright, I'll give this stuff a whirl once I'm up in the morning, thanks for the help I'll play around with this and see if I can get things working, if not I'll shoot up another message here, this is my final project and I think I'll finally be able to claim I understand C# a bit more than 8 weeks ago lol.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml.Serialization;

namespace maint_student_scores
{
    public class StudentDB
    {
        private const string dir = @"C:\C#.NET\Files\";
        private const string path = dir + "StudentScores.txt";

        public static List<Student> GetStudentScores()
        {
            // if the directory doesn't exist, create it
            if (!Directory.Exists(dir))
                Directory.CreateDirectory(dir);

            // create the object for the input stream for a text file
            StreamReader textIn =
                new StreamReader(
                new FileStream(path, FileMode.OpenOrCreate, FileAccess.Read));

            // create the list
            List<Student> students = new List<Student>();

            // read the data from the file and store it in the list
            while (textIn.Peek() != -1)
            {
                string row = textIn.ReadLine();
                string[] columns = row.Split('|');
                Student studentList = new Student();
                studentList.Name = columns[0];
                studentList.Score = columns[1];
                students.Add(studentList);
            }

            // close the input stream for the text file
            textIn.Close();

            return students;
        }

        public static void SaveStudents(List<Student> students)
        {
            // create the output stream for a text file that exists
            StreamWriter textOut =
                new StreamWriter(
                new FileStream(path, FileMode.Create, FileAccess.Write));

            // write each product
            foreach (Student s in students)
            {
                textOut.Write(s.Name + "|");
                textOut.WriteLine(s.Score);
            }

            // close the output stream for the text file
            textOut.Close();
        }
  }
}

I get an error at:

// write each product
            foreach (Student s in students)
            {
                textOut.Write(s.Name + "|");
                textOut.WriteLine(s.Score);
            }

About NullReferenceException was unhandled, object reference not set to an instance of an object. Do I need to recall the student list, or make it a public object outside of the first method above? Again I might be calling it wrong.

And I can't do it in xml (as much as I want to), it must be done to a text file.

Alright figured this out, redid my coding and its working good now. You code was a big help in figuring what I was doing wrong.

Once again you guys here rock and have helped me through learning C#, i'll definitely try my best to pay it forward and help others here when\if I can.

Thanks.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.