Question How do you read data from file once and then use it with different button events?

Wowywow

Member
Joined
Nov 9, 2019
Messages
16
Programming Experience
Beginner
Hi, so I had to make this app that would take data from text file ( Name, Gender, bDay, etc...) and would load it into dataGridView table. Also to add to that there needs to be 3 buttons to load only (females, males or anyone older than *set age*.
I pretty much did what I needed, but each button has to read that file every time. So I'am wondering how can I have that file be read once and then leave the buttons just to act as filters that would set the data?

C#:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }


        // Nuskaityti moterys
        private void button1_Click(object sender, EventArgs e)
        {
            string systemPath = System.IO.Directory.GetCurrentDirectory() + @"\txt1.txt";

            using (var streamReader = new System.IO.StreamReader(systemPath))
            {
                dataGridView1.Rows.Clear();
                while (!streamReader.EndOfStream)
                {
                    string line = streamReader.ReadLine();
                    string[] values = line.Split('\t');

                    for (int i=0; i<values.Length; i++)
                    {
                        string[] rez = values[i].Split(',');
                        rez[2] = rez[2].Trim();

                        if (rez[2].ToString() == "Moteris")
                        {
                            int rowIndex = dataGridView1.Rows.Add();
                            dataGridView1.Rows[rowIndex].Cells["Column1"].Value = rez[0];
                            dataGridView1.Rows[rowIndex].Cells["Column2"].Value = rez[1];
                            dataGridView1.Rows[rowIndex].Cells["Column3"].Value = rez[2];
                            dataGridView1.Rows[rowIndex].Cells["Column4"].Value = rez[3];
                            dataGridView1.Rows[rowIndex].Cells["Column5"].Value = rez[4];
                            dataGridView1.Rows[rowIndex].Cells["Column6"].Value = rez[5];
                        }
                    }
                }
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            string systemPath = System.IO.Directory.GetCurrentDirectory() + @"\txt1.txt";

            using (var streamReader = new System.IO.StreamReader(systemPath))
            {
                dataGridView1.Rows.Clear();
                while (!streamReader.EndOfStream)
                {
                    string line = streamReader.ReadLine();
                    string[] values = line.Split('\t');

                    for (int i = 0; i < values.Length; i++)
                    {
                        string[] rez = values[i].Split(',');
                        rez[2] = rez[2].Trim();

                        if (rez[2].ToString() == "Vyras")
                        {
                            int rowIndex = dataGridView1.Rows.Add();
                            dataGridView1.Rows[rowIndex].Cells["Column1"].Value = rez[0];
                            dataGridView1.Rows[rowIndex].Cells["Column2"].Value = rez[1];
                            dataGridView1.Rows[rowIndex].Cells["Column3"].Value = rez[2];
                            dataGridView1.Rows[rowIndex].Cells["Column4"].Value = rez[3];
                            dataGridView1.Rows[rowIndex].Cells["Column5"].Value = rez[4];
                            dataGridView1.Rows[rowIndex].Cells["Column6"].Value = rez[5];
                        }
                    }
                }
            }
        }

        private void button3_Click(object sender, EventArgs e)
        {
            string systemPath = System.IO.Directory.GetCurrentDirectory() + @"\txt1.txt";

            using (var streamReader = new System.IO.StreamReader(systemPath))
            {
                dataGridView1.Rows.Clear();
                while (!streamReader.EndOfStream)
                {
                    string line = streamReader.ReadLine();
                    string[] values = line.Split('\t');

                    for (int i = 0; i < values.Length; i++)
                    {
                        string[] rez = values[i].Split(',');
                        string date;

                        date = rez[5].Replace("-", "");
                        int today = int.Parse(DateTime.UtcNow.ToString("yyyyMMdd"));
                        int bDay = int.Parse(date);
                        int age = (today - bDay) / 10000;
                        int filterDate = Convert.ToInt32(textBox1.Text);

                        if (age >= filterDate)
                        {
                            int rowIndex = dataGridView1.Rows.Add();
                            dataGridView1.Rows[rowIndex].Cells["Column1"].Value = rez[0];
                            dataGridView1.Rows[rowIndex].Cells["Column2"].Value = rez[1];
                            dataGridView1.Rows[rowIndex].Cells["Column3"].Value = rez[2];
                            dataGridView1.Rows[rowIndex].Cells["Column4"].Value = rez[3];
                            dataGridView1.Rows[rowIndex].Cells["Column5"].Value = rez[4];
                            dataGridView1.Rows[rowIndex].Cells["Column6"].Value = rez[5];
                        }
                    }
                }
            }
        }
    }
}
Thanks in advance!
 

Sheepings

Senior Programmer
Joined
Sep 5, 2018
Messages
655
Location
UK
Programming Experience
10+
Can you provide the text file you are referring to.

I'm already envisioning reading it into an array, but I will know for sure once I see the text file.

Btw, welcome to the forums
 

Wowywow

Member
Joined
Nov 9, 2019
Messages
16
Programming Experience
Beginner
Can you provide the text file you are referring to.

I'm already envisioning reading it into an array, but I will know for sure once I see the text file.

Btw, welcome to the forums
Name, Surname, Gender, Email, Address, Date of birth
That's pretty much the format, I have filled the file out with:
Name1, Surname1, Female, Name1@Email.com, Street1, 2000-01-01
Name2, Surname2, Male, Name2@Email.com, Street2, 1988-01-06
And etc... For how long you want it ( for testing purposes I kept it simple ).

And thanks.
 

Sheepings

Senior Programmer
Joined
Sep 5, 2018
Messages
655
Location
UK
Programming Experience
10+
No, please attach the file to the forums as requested.
 

jmcilhinney

C# Forum Moderator
Staff member
Joined
Apr 23, 2011
Messages
2,511
Location
Sydney, Australia
Programming Experience
10+
You should start by reading the file into a DataTable, using either an OleDbDataAdapter or a TextFieldParser. The latter is declared in the Microsoft.VisualBasic.dll assembly, so you'd need to reference that. As with any object that you need to access at arbitrary times, you should assign the DataTable to a member variable, i.e. a field. You can then bind the DataTable to a BindingSource and bind that to your DataGridView. You can then filter the data by setting the Filter property of BindingSource, e.g.
C#:
myBindingSource.Filter = "Gender = 'Female'";
or:
C#:
var ageThreshold = Convert.ToInt32(ageNumericUpDown.Value);
var dateThreshold = DateTime.Today.AddYears(-ageThreshold);

myBindingSource.Filter = $"[Date of birth] <= #{dateThreshold:M/dd/yyyy}#";
 
Last edited:

Sheepings

Senior Programmer
Joined
Sep 5, 2018
Messages
655
Location
UK
Programming Experience
10+
I only answered this same question about 3,4 weeks ago on here and also back in june. The trouble with receiving this data from a text file requires the data to have the exact same structure each time. For example, can you guarantee there will be never a second Street? Because if there is, it will make whatever method you use unreliable when ciphering the text out. My question would be; is it possible to have the data in another format other than text, perhaps XML? Prevention is always better than the cure. However, if you are happy with how you receive this data currently, then John's reply will solve your second part of your problem.
 

Skydiver

Well-known member
Joined
Apr 6, 2019
Messages
646
Location
Virginia Beach, VA
Programming Experience
10+
And recall that the RFC5322 still for email addresses still has support for quoted strings, so the following is a legal email address:
Code:
"Last, First"@domain.com
Note the comma in the email address which is legal in this case because of the quotes.
 

jmcilhinney

C# Forum Moderator
Staff member
Joined
Apr 23, 2011
Messages
2,511
Location
Sydney, Australia
Programming Experience
10+
And recall that the RFC5322 still for email addresses still has support for quoted strings, so the following is a legal email address:
Code:
"Last, First"@domain.com
Note the comma in the email address which is legal in this case because of the quotes.
I was not aware of that. Of course, anyone who uses such an email address doesn't deserve to receive any email and I reckon that a lot of systems probably wouldn't accept it anyway.

Of course, well-written parsing code would handle that anyway, if the file was also well-written. If you escape any double-quotes with another double-quote and wrap any values that contains delimiters in double-quotes then a TextFieldParser will handle it and I'd wager that ADO.NET would too.
 

Wowywow

Member
Joined
Nov 9, 2019
Messages
16
Programming Experience
Beginner
I only answered this same question about 3,4 weeks ago on here and also back in june. The trouble with receiving this data from a text file requires the data to have the exact same structure each time. For example, can you guarantee there will be never a second Street? Because if there is, it will make whatever method you use unreliable when ciphering the text out. My question would be; is it possible to have the data in another format other than text, perhaps XML? Prevention is always better than the cure. However, if you are happy with how you receive this data currently, then John's reply will solve your second part of your problem.
Oh no, I'am only a first year and we are just covering the very basics of c#. We won't take up on anything very difficult this semester, so the text file will keep the same format always.
 

Skydiver

Well-known member
Joined
Apr 6, 2019
Messages
646
Location
Virginia Beach, VA
Programming Experience
10+
I reckon that a lot of systems probably wouldn't accept it anyway.
Yes, unfortunately a lot of "front-end" UI's don't accept it, the same way a lot of them also don't accept the '+', '{', or '}' symbols. I believe this is because they naively just skimmed through the RFC and/or just cribbed somebody else RegEx to validate email addresses. As stated all over the internet, email addresses SHOULD NOT be validated using regular expressions, yet people still do so.

Imposing limitations on the local part of the email address, should not be done, yet people still seem to do this. To me this sounds as unfair and culturally insensitive as saying that "you are only allowed to have exactly one first name, an optional have a middle name, and one last name -- in that order". The point of the local part was that it was up to the destination domain to do any further parsing. The only job that the message transfer agents have to do is to transmit the message to to the appropriate domain. They are not supposed to derive and special information from the local part. Yet, here we are with people writing UI's and impose limitations on the local part.

This is just like saying that '+' is not valid for use in the local part of an email address.
 

Sheepings

Senior Programmer
Joined
Sep 5, 2018
Messages
655
Location
UK
Programming Experience
10+
C#:
        public static readonly string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "mytext.txt");
        public static List<string[]> IEnum = new List<string[]>();
I stored the textfile on my desktop, and so the path points there and combines the path directory with the file name. The List<T> IEnum is a placeholder for each line read and they are broken up by the delimiter from the TextFieldParser which John previously recommended earlier. It's also IDisposible so you can nicely use it with using statements. The parser is actually very nice and It makes working with CSV files or even text files very easy by using the TextFieldParser.ReadFields Method (Microsoft.VisualBasic.FileIO). It also has some pretty nice properties such as : TextFieldParser.TrimWhiteSpace Property (Microsoft.VisualBasic.FileIO) for trimming any whitespace should you need or want to. It also allows you to check if your lines consist of words in quotations : TextFieldParser.HasFieldsEnclosedInQuotes Property (Microsoft.VisualBasic.FileIO).

Anyway, I started off with a button to get the data from the file into the IEnum (defined above), the IEnum stores List of string[] List<string[]> - this is where you will find your lines each with their own index in the list, and each index holds a string array entry where you can access the entries of data delimited by the comma for each line which was in the file and that's stored in the string array. See debugger :
Screenshot_43.jpg

C#:
        private void Button1_Click(object sender, EventArgs e)
        {
            using (FileStream reader = File.OpenRead(path))
            using (TextFieldParser iParse = new TextFieldParser(reader))
            {
                iParse.Delimiters = new[] { "," }; iParse.HasFieldsEnclosedInQuotes = false;
                do
                    IEnum.Add(iParse.ReadFields());
                while (!iParse.EndOfData);
            }
        }
Now that your file contents is properly structured in the IEnum List, you can iterate it to access the details like this :
C#:
        private void button2_Click(object sender, EventArgs e)
        {
            foreach (var (firstName, secondName)
                in from string[] line in IEnum
                   let firstName = line[0]
                   let secondName = line[1]
                   let genderType = line[2]
                   let emailAddress = line[3]
                   let personalAddress = line[4]
                   let personalDOB = line[5]
                   select (firstName, secondName))
            /* To get more variables, you need to extend Linq to iterate over and select the additional's */
            {
                Console.WriteLine($"Persons first name is : {firstName}");
                var fullName = string.Concat(firstName, string.Empty.PadRight(1), secondName);
                Console.WriteLine($"Persons Full Name is : {string.Concat(firstName, string.Empty.PadRight(1), secondName)}");
            }
        }
Sorry I used Linq, as it was force of habit, and I forgot I was writing it for the forum. But It's the same as simply using a foreach or a for loop.... I'm sure you will work it out - Oh what the hell, I'm in good mood. Try this :
C#:
        private void button3_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < IEnum.Count; i++)
            {
                Console.WriteLine(IEnum[i][0]);
                /* [i] iterates the IEnum, while [0] (if changed) will give you a different result, first name [0] second name be [1] etc */
            }
        }
With this, you now no longer need to keep reading the file. And while combining the above with this :
You should start by reading the file into a DataTable, using either an OleDbDataAdapter or a TextFieldParser. The latter is declared in the Microsoft.VisualBasic.dll assembly, so you'd need to reference that. As with any object that you need to access at arbitrary times, you should assign the DataTable to a member variable, i.e. a field. You can then bind the DataTable to a BindingSource and bind that to your DataGridView. You can then filter the data by setting the Filter property of BindingSource, e.g.
C#:
myBindingSource.Filter = "Gender = 'Female'";
or:
C#:
var ageThreshold = Convert.ToInt32(ageNumericUpDown.Value);
var dateThreshold = DateTime.Today.AddYears(-ageThreshold);

myBindingSource.Filter = $"[Date of birth] <= #{dateThreshold:M/dd/yyyy}#";
You should have a fully working application, just as you requested. If you get stuck or need any more info, post back to let us know.

Oh no, I'am only a first year and we are just covering the very basics of c#. We won't take up on anything very difficult this semester, so the text file will keep the same format always.
This is purely wishful thinking, and something I never tire to complain of, but I wish schools would put more effort into given more practical assignments. Keep in mind what I said about the comments above regarding the structure of the file. If your teacher decides to add a persons middle name to the file, this will throw everything I've done out of wack and It won't work as intended. Thus making your assignment a rather poor one in my opinion.

Hope it helps.
 
Last edited:
Top Bottom