Reading CSV file - Object Oriented way - c#

I'd like to parse a csv file in my course that I attend, The cvs file looks like this:
john; 3.5; 32111
etc
I've created a Class for that:
class Student
{
public string name { get; set; }
public double average { get; set; }
public int social_number { get; set; }
public Student(string name, double average, int social_number)
{
this.name = name;
this.average = average;
this.social_number = social_number;
}
public void CSV_digest(string csv_line)
{
if (csv_line != "")
{
string[] chunks = csv_line.Split(';');
name = chunks[0];
average = Convert.ToDouble(chunks[1]);
social_number = Convert.ToInt32(chunks[2]);
}
}
}
I don't really know how to propagate the Student type array:
class Program
{
static void Main(string[] args)
{
StreamReader csv = new StreamReader("students.csv", Encoding.UTF8);
string[] csv_lines = csv.ReadToEnd().Split('\n');
Student[] students = new Student[csv_lines.Length - 1];
for (int i = 0; i < csv_lines.Length; i++)
{
students[i] =
}
Console.ReadKey();
}
}
Could you please help me with this? I'd really like to utilize classes.

There is really no reason to use a library when the code to read CSV is very simple. See my code below :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
const string filename = #"c:\temp\test.csv";
static void Main(string[] args)
{
StreamReader csv = new StreamReader(filename);
string line = "";
List<Student> students = new List<Student>();
while((line = csv.ReadLine()) != null)
{
students.Add(new Student(line));
}
Console.ReadKey();
}
}
class Student
{
public string name { get; set; }
public double average { get; set; }
public int social_number { get; set; }
public Student(string csv_line)
{
if (csv_line != "")
{
string[] chunks = csv_line.Split(';');
name = chunks[0];
average = Convert.ToDouble(chunks[1]);
social_number = Convert.ToInt32(chunks[2]);
}
}
}
}

Related

How can I sort 4 seperate string arrays (with the same lenght), according to one of them in alphabetical order? (in C#)

I have read out per WMI the installed programs on a remote PC. I have read the Program Name, Program Publisher, Program Install.date and Program install.path properties and stored each of them in a separate string array. (All arrays with same length: 99)
I want to list the program informations according to the alphabetical order of Program name.
Is it possible to do that without combining the 4 arrays in one multidimensional array?
Or should I first combine the arrays to one two dimensional array ?
If yes how?
As I am new in C# I would thank you if you would make a suggestion. I have read lots of entries but I got more confused.
public string[] Programs_WMI_name = new string[99];
public string[] Programs_WMI_publisher = new string[99];
public string[] Programs_WMI_installdate = new string[99];
public string[] Programs_WMI_installlocation = new string[99];
I have tried this but get error:
In my public Class
public class TagService{
public string Programs_WMI_Name { get; set; }
public string Programs_WMI_Publisher { get; set; }
public string Programs_WMI_Installdate { get; set; }
public string Programs_WMI_Installlocation { get; set; }
public List<string> programs = new List<string>(99);
}
then
for (int i = 0; i < TagService.Programs_WMI_name.Length; i++)
{
programs.Add(new TagService
{
Programs_WMI_Name = TagService.Programs_WMI_name[i],
Programs_WMI_Publisher = TagService.Programs_WMI_publisher[i],
Programs_WMI_Installdate = TagService.Programs_WMI_installdate[i],
Programs_WMI_Installlocation = TagService.Programs_WMI_installlocation[i],
});
}
programs = programs.OrderBy(p => p.Programs_WMI_Name).ToList();
Do yourself and others a favor and use classes
public class ProgramInfo
{
public string Name { get; set; }
public string Publisher { get; set; }
public string InstallDate { get; set; }
public string InstallLocation { get; set; }
}
from arrays
var programs = new List<ProgramInfo>(Programs_WMI_name.Length);
for (int i = 0; i < Programs_WMI_name.Length; i++)
{
programs.Add(new ProgramInfo
{
Name = Programs_WMI_name[i],
Publisher = Programs_WMI_publisher[i],
InstallDate = Programs_WMI_installdate[i],
InstallLocation = Programs_WMI_installlocation[i],
});
}
better yet fill from query directly
var programs = new List<ProgramInfo>();
foreach (var row in new ManagementObjectSearcher(somequery).Get())
{
programs.Add(new ProgramInfo
{
Name = row["name"],
Publisher = row["publisher"],
InstallDate = row["installdate"],
InstallLocation = row["installlocation"],
});
}
complete example could look like this
using System;
using System.Linq;
using System.Collections.Generic;
namespace Test
{
public class ProgramInfo
{
public string Name { get; set; }
public string Publisher { get; set; }
public string InstallDate { get; set; }
public string InstallLocation { get; set; }
}
public class TagService
{
public static List<ProgramInfo> Programs { get; } = new List<ProgramInfo>();
public static void RefreshPrograms()
{
Programs.Clear();
foreach (var row in new ManagementObjectSearcher(somequery).Get())
{
programs.Add(new ProgramInfo
{
Name = row["name"],
Publisher = row["publisher"],
InstallDate = row["installdate"],
InstallLocation = row["installlocation"],
});
}
Programs.Sort((l, r) => string.Compare(l.Name, r.Name));
}
}
public Program
{
public static void Main()
{
TagService.ReadPrograms();
var properties = typeof(ProgramInfo).GetProperties();
Console.WriteLine(string.Join("|", properties.Select(p => p.Name.PaddRight(10))));
foreach (var program in TagService.Programs)
{
Console.WriteLine(string.Join("|", properties.Select(p => ((string)p.GetValue(program)).PaddRight(10))));
}
}
}
}

Passing Data From Text File to Constructor

I'm looking for a way to pass information from a text file into a constructor so that I can create an array of that constructor object with each object in the array holding information from the rows of the text file.
The constructor is formatted as follows:
public Member(string name, int number, decimal rate, double hours)
While the text file is formatted as such:
Eric Wallace, 352456, 15.88, 32.20
Clara Kell, 233424, 35.88, 18.76
Darren Price, 656795, 27.82, 20.25
etc...
and each Member will go into an array.
In the end, what I need is for each row to be split up and passed to the constructor in a way where each row becomes its own member in an array so that they can be output one after another in a loop or called individually as rows.
My approach would begin with making an interface that all my "buildable" data types will implement. I want my data models deciding how they are built from a string:
public interface IBuildableFromString
{
public IBuildableFromString Build(string str, string seperator = ",");
}
Then make Member implement it like so:
public class Member : IBuildableFromString
{
public string Name { get; set; }
public int Number { get; set; }
public decimal Rate { get; set; }
public double Hours { get; set; }
public Member() { }
public Member(string name, int number, decimal rate, double hours)
{
Name = name;
Number = number;
Rate = rate;
Hours = hours;
}
public IBuildableFromString Build(string str, string seperator = ",")
{
try
{
string[] parts = str.Split(seperator);
return new Member(parts[0], int.Parse(parts[1]),
decimal.Parse(parts[2]), double.Parse(parts[3]));
}
catch
{
return null;
}
}
}
Then the method to read the file and build the object data:
public static T[] BuildData<T>(string filePath) where T :
IBuildableFromString, new()
{
List<T> dataObjects = new List<T>();
string[] lines = File.ReadAllLines(filePath);
foreach (string line in lines)
{
if (!String.IsNullOrEmpty(line))
{
var newMember = new T().Build(line);
if (newMember != null)
dataObjects.Add((T)newMember);
}
}
return dataObjects.ToArray();
}
Lastly, call the function above like so:
static void Main(string[] args)
{
var data = BuildData<Member>(#"path_to_your_file.txt");
}
It probably needs more error checking, but this was the most extensible way I could think of doing it. Cheers!
As long as your file is well-formed, then this would work:
Member[] members =
File
.ReadLines(#"mytextfile.txt")
.Select(x => x.Split(',').Select(y => y.Trim()).ToArray())
.Select(x => new Member(x[0], int.Parse(x[1]), decimal.Parse(x[2]), double.Parse(x[3])))
.ToArray();
I will use StreamReader to read the txt file, then use replace to eliminate spaces, and then use split to split the data.
Use StreamReader to read text from a file:
StreamReader sr = new StreamReader(#"C:\demo\de.txt")
Make Member implement it like so:
public class Member {
public string Name { get; set; }
public int Number { get; set; }
public decimal Rate { get; set; }
public double Hours { get; set; }
public Member(string name, int number, decimal rate, double hours) {
Name = name;
Number = number;
Rate = rate;
Hours = hours;
}
}
Call the data like this:
foreach (var item in members) {
Console.WriteLine($"{ item.Name} { item.Number} { item.Rate} { item.Hours}");
}
Total code:
using System;
using System.Collections.Generic;
using System.IO;
namespace ConsoleApp2 {
class Program {
static void Main(string[] args) {
List<Member> members = new List<Member>();
try {
// Create an instance of StreamReader to read from a file.
// The using statement also closes the StreamReader.
using (StreamReader sr = new StreamReader(#"C:\demo\de.txt")) {
string line;
// Read and display lines from the file until the end of
// the file is reached.
while ((line = sr.ReadLine()) != null) {
line = line.Replace(" ", "");
string[] tmp = line.Split(',');
string name = tmp[0];
int number = Convert.ToInt32(tmp[1]);
decimal rate = Convert.ToDecimal(tmp[2]);
double hours = Convert.ToDouble(tmp[3]);
members.Add(new Member(name, number, rate, hours));
}
}
} catch (Exception e) {
// Let the user know what went wrong.
Console.WriteLine("The file could not be read:");
Console.WriteLine(e.Message);
}
foreach (var item in members) {
Console.WriteLine($"{ item.Name} { item.Number} { item.Rate} { item.Hours}");
}
Console.ReadLine();
}
public class Member {
public string Name { get; set; }
public int Number { get; set; }
public decimal Rate { get; set; }
public double Hours { get; set; }
public Member(string name, int number, decimal rate, double hours) {
Name = name;
Number = number;
Rate = rate;
Hours = hours;
}
}
}
}
If you have questions, please add a comment.

How to print a name from a list c#

So I'm working on a library management system and I'm new to C# so you may see me here a lot, the issue I'm currently having revolves around this. I'm trying to make it search in my list for the author and it succeeds in doing that, I just don't know how to make it print out the result to make it appear on the console as it currently just prints "Author exists!".
public static void LetaEfterBok()
{
Console.Write("Enter an author to search for a book: ");
string search = Console.ReadLine();
foreach (Bok b in newBok)
{
Bok Bok = new Bok();
if (b.namn.Equals(search))
Console.Write("Author " + Bok.Författare + " exists!");
}
}
If needed, here is the lists and variables
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace Bibliotek
{
//Definerar klassen Bok
class Bok
{
public string ID
{ get; set; }
public int tempID;
public string Författare
{ get; set; }
public string namn
{ get; set; }
public int BokCount;
public int x;
}
class Program
{
static List<Bok> newBok = new List<Bok>();
static List<BorrowDetails> borrowList = new List<BorrowDetails>();
static Bok Bok = new Bok();
static BorrowDetails borrow = new BorrowDetails();
//Menyn och startsidan till programmet
static void Main(string[] args)
{
StreamReader readFile = new StreamReader("bokfil.txt");
string s;
while((s = readFile.ReadLine()) != null)
{
Bok Bok = new Bok();
string[] BokData = s.Split(',');
Bok.namn = BokData[0];
Bok.Författare = BokData[1];
Bok.ID = BokData[2];
Bok.tempID = int.Parse(Bok.ID);
newBok.Add(Bok);
}
readFile.Close();
try if this method works for you...
public void LetaEfterBok()
{
Console.Write("Enter an author to search for a book: ");
string search = Console.ReadLine();
var book = newBok.FirstOrDefault(b => { return b.namn.Equals(search, StringComparison.OrdinalIgnoreCase); } );
if(book != null)
{
Console.WriteLine("Author " + book.Författare + " exists!");
}
}
I suggest you do the OOP thing and give your class Bok some functionality to display information about itself. You should override the ToString() method such that anytime you do WriteLine(b) where b is a Bok it would print a string with information of the book.
For example:
//Definerar klassen Bok
class Bok
{
public string ID
{ get; set; }
public int tempID;
public string Författare
{ get; set; }
public string namn
{ get; set; }
public int BokCount;
public int x;
public override string ToString()
{
return $"Title:{Författare}, Author:{namn}, ID:{ID} ({BokCount} Count)";
}
}
which can be used in the search as
public static void LetaEfterBok()
{
Console.Write("Enter an author to search for a book: ");
string search = Console.ReadLine();
foreach (Bok b in newBok)
{
if (b.namn.Equals(search))
{
Console.Write($"{b} Exists!");
}
}
}
To add more flexibility, also add a function in the Bok class that tries to match the author, and use the List<T>.Find() method to search the list
//Definerar klassen Bok
public class Bok
{
public string ID { get; set; }
public int tempID;
public string Författare { get; set; }
public string namn { get; set; }
public int BokCount;
public int x;
public override string ToString()
{
return $"Author:{Författare}, Name:{namn}, ID:{ID} ({BokCount} Count)";
}
public bool MatchAuthor(string name) => namn.ToUpper().StartsWith(name.ToUpper());
}
public static void LetaEfterBok()
{
Console.Write("Enter an author to search for a book: ");
string search = Console.ReadLine();
Bok match = newBok.Find((b) => b.MatchAuthor(search));
if (match!=null)
{
Console.Write($"{b} Exists!");
}
}

How do I write at a specific index of a line?

Good day Stackoverflow,
I want to write some text at a specific point of a line in a txt-file.
So I want to write something between two ; in the line.
The Line of the textfile is: 20180912_0149;KIV\vischer;12.09.2018;01:49;; .
I want to write it if I click the "Geht" Button. I tried different things with streamreader and writer but I don't get to a solution.
Here is my code of the aspx.cs and my helper class:
Aspx.cs:
namespace Zieterfassung_0._0._2pre_alpha
{
public partial class Zeiten : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string sPath = #"C:\VSTO\Projects\Zeiterfassung\Zeiterfassung\obj\Debug\Zeiten.txt";
tb_User.Text = WindowsIdentity.GetCurrent().Name.ToString();
tb_Datum.Text = DateTime.Now.ToString("dd.MM.yyyy");
tb_Zeit.Text = DateTime.Now.ToString("hh:mm");
cZeile KommtDatumZeit = new cZeile();
if (File.Exists(sPath))
{
using (StreamReader sr = new StreamReader(sPath))
{
while (!sr.EndOfStream)
{
KommtDatumZeit = cZeiterfassung.GetZeileObjectFromZeileString(sr.ReadLine(), ";");
}
}
}
tb_Kommt.Text = KommtDatumZeit.dtKommt.ToString();
}
protected void btn_Geht_Click(object sender, EventArgs e)
{
string sAusgabeGeht = string.Format("{0:hh:mm}", tb_Zeit.Text);
string sPath = #"C:\VSTO\Projects\Zeiterfassung\Zeiterfassung\obj\Debug\Zeiten.txt";
FileInfo fi = new FileInfo(sPath);
cZeile Geht = new cZeile();
using (StreamReader sr = new StreamReader(sPath))
{
Geht = cZeiterfassung.GetZeileObjectFromZeileString(sr.ReadLine(), ";");
}
using(StreamWriter sw = new StreamWriter(sPath))
{
}
}
}
}
Helperclass for splitting and array:
namespace Prog
{
public static class cZeiterfassung
{
public static cZeile GetZeileObjectFromZeileString(string Zeile, string Trenner)
{
cZeile ZeileReturn = new cZeile();
string[] separators = { Trenner };
string[] arZeile = Zeile.Split(separators, StringSplitOptions.None);
ZeileReturn.ID = arZeile[0];
if (arZeile[1].IndexOf("\\") != -1)
{
ZeileReturn.Domain = arZeile[1].Substring(0, arZeile[1].IndexOf("\\"));
if (arZeile[1].Length >= arZeile[1].IndexOf("\\"))
ZeileReturn.User = arZeile[1].Substring(arZeile[1].IndexOf("\\") + 1);
}
else
ZeileReturn.User = arZeile[1];
ZeileReturn.Datum = arZeile[2];
ZeileReturn.Kommt = arZeile[3];
ZeileReturn.Geht = arZeile[4];
if(!string.IsNullOrEmpty(arZeile[2]))
ZeileReturn.dtDatum = Convert.ToDateTime(arZeile[2]);
if(!string.IsNullOrEmpty(arZeile[3]))
ZeileReturn.dtKommt = Convert.ToDateTime(arZeile[3]);
if (!string.IsNullOrEmpty(arZeile[4]))
ZeileReturn.dtGeht = Convert.ToDateTime(arZeile[4]);
return ZeileReturn;
}
}//cZeiterfassung
public class cZeile
{
public string ID { get; set; }
public string Domain { get; set; }
public string User { get; set; }
public string Datum { get; set; }
public string Kommt { get; set; }
public string Geht { get; set; }
public DateTime dtDatum { get; set; }
public DateTime dtKommt { get; set; }
public DateTime dtGeht { get; set; }
public string Dauer { get; set; }
}
}
I can't quite Point out what are you trying to do from your code, but from the question you asked:
I would look into every line if you are looking for a specific line
string Data = "";
using(StreamReader Sr = new StreamReader(Path))
{
while(!Sr.EndOfStream())
{
string UseMe = Sr.ReadLine();
Data += UseMe;
}
}
Now you could just validate each line. With the Data-string I gave you a possibility to build each line into one string
I hope I could help you, otherwise contact me directly (I also speak german I guess this is easier for you)
If your file isn't big, I propose you to write to new files with new data.
This is the idea
string[] lines = File.ReadAllLines(sPath);
for (int i = 0; i < lines.Length; i++)
{
if (lines[i].IndexOf(";;") != -1)
{
lines[i] = lines[i].Insert(line.IndexOf(";;"), "xxx");
}
}
File.WriteAllLines(sPathTemp, lines);

match value in one list with another and write value to other list

I have one list that is written to this class:
public class keyfrs
{
public keyfrs() { }
public long regID { get; set; }
public long ID { get; set; }
public string county { get; set; }
public string state { get; set; }
}
List<keyfrs> k = {1,2,3,4}] regID
{A,B,C,D} ID
I have another list class like this:
public class states
{
public states() { }
public long regID { get; set; }
public string state { get; set; }
public string county { get; set; }
}
List<states> s = {1,2,3,4}regID
{MA,NY,CT}state
{Suffolk,NY,Hampden}county
Want to write the county and state to the keyfrs list that matches with the regID from the lists.
What my program does so far is parse in two files and write each one to the different class list it corresponds to. As you can see both classes have a regID column. What I need to do is match the two lists together on regID and write the county and state to the keyfrs list class to then output that list to a new file with these added column in it.
static void Main(string[] args)
{
PARSEkeYfrs();
parsestateFile();
matchValues();
outputFile();
}
private static void outputFile()
{
string filename = #"c:\keyswCounty.csv";
using(StreamWriter write = new StreamWriter(filename))
{
write.WriteLine("RegIF"+","+"ID"+","+"County"+","+"State");
foreach(keyfrs k in keysandID)
{
write.WriteLine(k.regID +"," +k.ID+","+k.county+","+k.state);
}
}
}
private static void matchValues()
{
foreach(keyfrs k in keysandID)
{
}
}
private static void parsestateFile()
{
int a = 0;
string filename = #"c:\ALLStates.txt";
using (StreamReader read = new StreamReader(filename))
{
read.ReadLine();
while (!read.EndOfStream)
{
a++;
try{
string line = read.ReadLine();
string[] splitline = line.Split(',');
if(splitline[1]!="")
{
states s = new states();
s.regID = Convert.ToInt64(splitline[0]);
s.county = Convert.ToString(splitline[1]);
s.state = Convert.ToString(splitline[2]);
stateFile.Add(s);
}
}
catch(Exception ex)
{
string.Format("error:{0}" + ex.Message.ToString());
}
}
}
}
private static void PARSEkeYfrs()
{ int a = 0;
string filename = #"c:\key_frs.csv";
using (StreamReader read = new StreamReader(filename))
{
read.ReadLine();
while (!read.EndOfStream)
{
try{
a++;
string line = read.ReadLine();
string[] splitline = line.Split(',');
if(splitline[1]!="")
{
keyfrs k = new keyfrs();
k.regID = Convert.ToInt64(splitline[0]);
k.ID = Convert.ToInt64(splitline[1]);
k.county = "";
k.state = "";
keysandID.Add(k);
}
}
catch(Exception ex)
{
string.Format("error:{0}"+ex.Message.ToString());
}
}
}
}
switched the state list to a dictionary and matched the values by the key value pair by using the TryGetValue method.

Categories

Resources