My professor gave the class an example of C# that can be used to split data from a text file. I am trying to use it for a project that involves splitting the contents of a txt. file into 4 arrays or fields. Here is the code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
class Program
{
static void Main()
{
int i = 0;
foreach (string line in File.ReadAllLines("census.txt"))
{
string[] parts = line.Split(',');
foreach (string part in parts)
{
Console.WriteLine("{0}",
part);
}
i++;
}
}
}
Here is census.txt:
21,f, s, 14
41,f, m, 22
12, m, s, 12
11, f, s, 8
29, m, m, 4
6, m, s, 12
9, f, s, 2
30, f, s, 1
It's supposed to be hypothetical census data going by age, gender, marital status, and district. The output I keep getting is each of those numbers or chars in a single line like so:
21
f
s
14
41
f
m
22
and so on.
I think it means it's working but I'd like to know how to use this for entering into 4 parallel arrays. I would also to know more about splitting it into 4 fields, structs, or classes. The next part of the project involves counting every time a certain age number or district number appears and that will involve a lot of arrays.
I would extend irsog's answer a bit:
Use a class instead of a structure
Use properties instead of fields
Use Gender and MaritalStatus enums instead of plain strings
Code:
public class Person
{
public int Age { get; set; }
public MaritalStatus MaritalStatus { get; set; }
public Gender Gender { get; set; }
public int District { get; set; }
}
public enum MaritalStatus
{
Single, Married
}
public enum Gender
{
Male, Female
}
And usage:
var people = new List<Person>();
foreach (string line in File.ReadAllLines("Input.txt"))
{
string[] parts = line.Split(',');
people.Add(new Person() {
Age = int.Parse(parts[0]),
MaritalStatus = parts[1] == "s" ? MaritalStatus.Single : MaritalStatus.Married,
Gender = parts[2] == "m" ? Gender.Male : Gender.Female,
District = int.Parse(parts[3])
});
}
This is old thread, but as google shows it among first few pages I decided to send my comment. I strongly advise against given txt file format, because it is not error proof. If census.txt is not guaranteed to be ideal and especially if it is supposed to be created by some third party (user, administrator, whoever) then I strongly recommend records to be ended with some symbol, like this:
21,f, s, 14;
41,f, m, 22;
then first thing what we do - we get array of records, like this:
string[] lines = text.split(';');
then simply split again - this time to get record elements.
foreach (string record in lines)
{
string[] fields = record.split(',');
}
This way it is not only easier to read records/fields, but also you can easily check consistency of file, ignore errors (empty records), check number of fields in each records and etc.
A generic list (as used in the other 2 current answers here) is the best way to go. However, if you need to have the data in arrays (as your previous question seems to indicate), then you can modify your professor's code like this:
C#
int[] districtDataD = new int[900];
string[] districtDataG = new string[900];
string[] districtDataM = new string[900];
int[] districtDataA = new int[900];
int i = 0;
foreach (string line in File.ReadAllLines("census.txt"))
{
string[] parts = line.Split(',');
districtDataD[i] = int.Parse(parts[0]);
districtDataS[i] = parts[1];
districtDataM[i] = parts[2];
districtDataA[i] = int.Parse(parts[3]);
i++;
}
VB.NET (Since your original question was tagged with VB.NET):
Dim districtDataD() As New Integer(900)
Dim districtDataS() As New String(900)
Dim distrcitDataM() As New String(900)
Dim districtDataA() As New Integer(900)
Dim i As Integer = 0
For Each Dim line As String In File.ReadAllLines("census.txt")
Dim string() As parts = line.Split(',')
districtDataD(i) = Integer.Parse(parts(0))
districtDataS(i) = parts(1)
districtDataM(i) = parts(2)
districtDataA(i) = Integer.Parse(parts(3))
i++
Next
You could also use a struct or class and have one array that holds that object, but it looks like you're professor wants you to use 4 separate arrays. If you can use one, you can simply declare the array like this, for example:
C#
Person[] districtData = new Person[900];
VB.NET
Dim districtData() As New Person(900)
Then you could do this inside the split logic (note that if, say Distric and Age are integers in your object you'll have to cast or parse them as I show below):
C#
districtData[i] = new Person() { District = int.Parse(parts[0]), Gender = parts[1], MaritalStatus = parts[2], Age = int.Parse(parts[3]) };
VB.NET
districtData[i] = new Person() With { .District = Integer.Parse(parts[0]), .Gender = parts[1], .MaritalStatus = parts[2], .Age = Integer.Parse(parts[3]) }
There's a risk with this code that if you have more than 900 lines of data, you will get an index out of range exception. One way to avoid this would be to modify the code I put above with a while loop that checks the bounds of the target array(s) or the the number of lines haven't been exceed, like this:
C#
string[] lines = File.ReadAllLines("census.txt");
int i = 0;
while (i < 900 && i < parts.Length)
{
// split logic goes here
}
VB.NET
Dim lines As String() = File.ReadAllLines("census.txt")
Dim i As Integer = 0
While (i < 900 AndAlso i < lines.Length)
' split logic goes here
End While
I haven't tested the code, but this will hopefully help you if you must use arrays.
You can Make a structure for required information:
public struct Info
{
public int Age;
public string gender;
public string status;
public int district;
}
and inset data to your structure list:
List<Info> info = new List<Info>();
foreach (string line in File.ReadAllLines("census.txt"))
{
string[] parts = line.Split(',');
info.Add(new Info() {Age=int.Parse(parts[0]), gender=parts[1], status=parts[2], district=int.Parse(parts[3]) });
}
Now yo have a list of person information.
Related
I try to build some table inside a text file which
look like this:
Name Grade
--------------------
John 100
Mike 94
...
...
I have this bunch of code:
List<string> NamesList = new List<string>();
List<int> Grades = new List<int>();
Grades.Add(98);
Grades.Add(100);
NamesList.Add("John");
NamesList.Add("Alon");
if (NamesList.Count() == Grades.Count())
{
var length = NamesList.Count();
var min = Grades.Min();
var max = Grades.Max();
using (System.IO.StreamWriter myF =
new System.IO.StreamWriter(#"C:\Users\axcel\textfolder\myFile.txt", true))
{
for (int i = 0; i < length; i++)
{
if (i == 0)
{
myF.WriteLine("Name Age Grade");
myF.WriteLine("==================================");
}
myF.WriteLine(NamesList.ElementAt(i));
myF.WriteLine(" ");
myF.WriteLine(Grades.ElementAt(i));
}
}
}
but my problem is that writing the grades after the names it is writing in a new line. I thought of writing it together to a string and to streaming it but I want to avoid an extra computing...
How can I solve it?
WriteLine() always add a new line after your text. So in your case it should be
myF.Write(NamesList.ElementAt(i));
myF.Write(" ");
myF.WriteLine(Grades.ElementAt(i));
var students = new List<(string name, int age, int grade)>()
{
("John", 21, 98),
("Alon", 45, 100)
};
students.Add(("Alice", 35, 99));
using (var writer = new StreamWriter("myFile.txt"))
{
writer.WriteLine(string.Join("\t", "Name", "Age", "Grade"));
foreach(var student in students)
{
writer.WriteLine(string.Join("\t", student.name, student.age, student.grade));
}
}
As some comments have suggested you could use a Student class to group name, age and grade. In this example I've used a Value Tuple instead.
You can see how it improves the readability of the code and you can focus on the problem you are actually trying to solve. You can reduce your write operation to a simple, readable expression - meaning you are less likely to make mistakes like mixing up Write and WriteLine.
You can always align the text by using string interpolation alignment.
To follow some of the comments, I also urge you to build a class holding the values.
public class Student
{
public string Name { get; set; }
public int Age { get; set; }
public int Grade { get; set; }
}
And here is the code using string interpolation alignment
var students = new List<Student>
{
new Student {Name = "John", Age = 10, Grade = 98},
new Student {Name = "Alon", Age = 10, Grade = 100}
};
var minGrade = students.Min(s => s.Grade);
var maxGrade = students.Max(s => s.Grade);
using (var myF = new System.IO.StreamWriter(#"C:\Users\axcel\textfolder\myFile.txt", true))
{
myF.WriteLine($"{"Name",-15}{"Age",-10}{"Grade",5}");
myF.WriteLine("==============================");
foreach (var student in students)
{
myF.WriteLine($"{student.Name,-15}{student.Age,-10}{student.Grade,5}");
}
}
This will produce the following result:
Name Age Grade
==============================
John 10 98
Alon 10 100
Positive numbers are right-aligned and negative numbers are left-aligned
You can read more about it on the string interpolation page at Microsoft Docs
To solve the issue you are having, you could just use:
myF.WriteLine(NamesList.ElementAt(i) + " " + Grades.ElementAt(i));
However the code you provided would benefit from being modified as described in the comments (create a class, use FileHelpers, etc.)
Solution 1:
Why you are not trying the concatenating the two string like:
string line = NamesList.ElementAt(i) + " " + Grades.ElementAt(i);
myF.WriteLine(line);
OR
Solution 2:
What you are using is WriteLine("Text") function which always writes the text to next line. Instead you can use Write("Text") function which will write the string on same line. you can try like:
myF.Write(NamesList.ElementAt(i));
myF.Write(" ");
myF.Write(Grades.ElementAt(i));
myF.WriteLine(); // Here it will enter to new line
I've been looking around a bit but haven't really found a good example with what I'm struggling right now.
I have a .txt file with a couple of columns as follows:
# ID,YYYYMMDD, COLD,WATER, OD, OP,
52,20120406, 112, 91, 20, 130,
53,20130601, 332, 11, 33, 120,
And I'm reading these from the file into a string[] array.
I'd like to split them into a list
for example
List results, and [0] index will be the first index of the columns
results[0].ID
results[0].COLD
etc..
Now I've been looking around, and came up with the "\\\s+" split
but I'm not sure how to go about it since each entry is under another one.
string[] lines = File.ReadAllLines(path);
List<Bus> results = new List<Bus>();
//Bus = class with all the vars in it
//such as Bus.ID, Bus.COLD, Bus.YYYYMMDD
foreach (line in lines) {
var val = line.Split("\\s+");
//not sure where to go from here
}
Would greatly appreciate any help!
Kind regards, Venomous.
I suggest using Linq, something like this:
List<Bus> results = File
.ReadLines(#"C:\MyFile.txt") // we have no need to read All lines in one go
.Skip(1) // skip file's title
.Select(line => line.Split(','))
.Select(items => new Bus( //TODO: check constructor's syntax
int.Parse(items[1]),
int.Parse(items[3]),
DateTime.ParseExact(items[2], "yyyyMMdd", CultureInfo.InvariantCulture)))
.ToList();
I would do
public class Foo
{
public int Id {get; set;}
public string Date {get; set;}
public double Cold {get; set;}
//...more
}
Then read the file
var l = new List<Foo>();
foreach (line in lines)
{
var sp = line.Split(',');
var foo = new Foo
{
Id = int.Parse(sp[0].Trim()),
Date = sp[1].Trim(),//or pharse the date to a date time struct
Cold = double.Parse(sp[2].Trim())
}
l.Add(foo);
}
//now l contains a list filled with Foo objects
I would probably keep a List of properties and use reflection to populate the object, something like this :
var columnMap = new[]{"ID","YYYYMMDD","COLD","WATER","OD","OP"};
var properties = columnMap.Select(typeof(Bus).GetProperty).ToList();
var resultList = new List<Bus>();
foreach(var line in lines)
{
var val = line.Split(',');
var adding = new Bus();
for(int i=0;i<val.Length;i++)
{
properties.ForEach(p=>p.SetValue(adding,val[i]));
}
resultList.Add(adding);
}
This is assuming that all of your properties are strings however
Something like this perhaps...
results.Add(new Bus
{
ID = val[0],
YYYYMMDD = val[1],
COLD = val[2],
WATER = val[3],
OD = val[4],
OP = val[5]
});
Keep in mind that all of the values in the val array are still strings at this point. If the properties of Bus are typed, you will need to parse them into the correct types e.g. assume ID is typed as an int...
ID = string.IsNullOrEmpty(val[0]) ? default(int) : int.Parse(val[0]),
Also, if the column headers are actually present in the file in the first line, you'll need to skip/disregard that line and process the rest.
Given that we have the Bus class with all the variables from your textfile:
class Bus
{
public int id;
public DateTime date;
public int cold;
public int water;
public int od;
public int op;
public Bus(int _id, DateTime _date, int _cold, int _water, int _od, int _op)
{
id = _id;
date = _date;
cold = _cold;
water = _water;
od = _od;
op = _op;
}
}
Then we can list them all in the results list like this:
List<Bus> results = new List<Bus>();
foreach (string line in File.ReadAllLines(path))
{
if (line.StartsWith("#"))
continue;
string[] parts = line.Replace(" ", "").Split(','); // Remove all spaces and split at commas
results.Add(new Bus(
int.Parse(parts[0]),
DateTime.ParseExact(parts[1], "yyyyMMdd", CultureInfo.InvariantCulture),
int.Parse(parts[2]),
int.Parse(parts[3]),
int.Parse(parts[4]),
int.Parse(parts[5])
));
}
And access the values as you wish:
results[0].id;
results[0].cold;
//etc.
I hope this helps.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I have this text file that only has one row. Each file contains one customer name but multiple items and descriptions.
Record starting with 00 (Company Name) has a char length of 10
01 (Item#) - char length of 10
02 (Description) - char length of 50
I know how to read a file, but I don't have any idea of how to loop through only one line, find records 00, 01, 02 and grab the text based on the length, finally start at the position of the last records and start the loop again. Can someone please give me an idea of how to read files like this?
output:
companyName 16622 Description
companyName 15522 Description
input text file example
00Init 0115522 02Description 0116622 02Description
This solution assumes that the data is fixed width, and that item number will preceed description (01 before 02). This solution will emit a record every time a description record is encountered, and deals with multiple products for the same company.
First, define a class to hold your data:
public class Record
{
public string CompanyName { get; set; }
public string ItemNumber { get; set; }
public string Description { get; set; }
}
Then, iterate through your string, returning a record when you've got a description:
public static IEnumerable<Record> ReadFile(string input)
{
// Alter these as appropriate
const int RECORDTYPELENGTH = 2;
const int COMPANYNAMELENGTH = 41;
const int ITEMNUMBERLENGTH = 8;
const int DESCRIPTIONLENGTH = 48;
int index = 0;
string companyName = null;
string itemNumber = null;
while (index < input.Length)
{
string recordType = input.Substring(index, RECORDTYPELENGTH);
index += RECORDTYPELENGTH;
if (recordType == "00")
{
companyName = input.Substring(index, COMPANYNAMELENGTH).Trim();
index += COMPANYNAMELENGTH;
}
else if (recordType == "01")
{
itemNumber = input.Substring(index, ITEMNUMBERLENGTH).Trim();
index += ITEMNUMBERLENGTH;
}
else if (recordType == "02")
{
string description = input.Substring(index, DESCRIPTIONLENGTH).Trim();
index += DESCRIPTIONLENGTH;
yield return new Record
{
CompanyName = companyName,
ItemNumber = itemNumber,
Description = description
};
}
else
{
throw new FormatException("Unexpected record type " + recordType);
}
}
}
Note that your field lengths in the question don't match the sample data, so I adjusted them so that the solution worked with the data you provided. You can adjust the field lengths by adjusting the constants.
Use this like the following:
string input = "00CompanyName 0115522 02Description 0116622 02Description ";
foreach (var record in ReadFile(input))
{
Console.WriteLine("{0}\t{1}\t{2}", record.CompanyName, record.ItemNumber, record.Description);
}
If you read the whole file into a string, you have a couple options.
One, it might be useful to use string.split.
Another option would be to use string.indexof. Once you have the index, you could use string.substring
Assuming fixed-width as specified, lets create two simple classes to hold a client and its related data as a list:
// can hold as many items (data) as there are in the line
public class Client
{
public string name;
public List<ClientData> data;
};
// one single item in the client data
public class ClientData
{
public string code;
public string description;
};
To parse a single line (which is assumed to have a single client and a successive list of item/description), we can do this (note: for simplification I'm just creating a static class with a static method in it):
// this parser will read as many itens as there are in the line
// and return a Client instance with those inside.
public static class Parser
{
public static Client ParseData(string line)
{
Client client = new Client ();
client.data = new List<ClientData> ();
client.name = line.Substring (2, 10);
// remove the client name
line = line.Substring (12);
while (line.Length > 0)
{
// create new item
ClientData data = new ClientData ();
data.code = line.Substring (2, 10);
data.description = line.Substring (14, 50);
client.data.Add (data);
// next item
line = line.Substring (64);
}
return client;
}
}
So, in your main loop, just after reading a new line from the file, you can call the above method to receive a new client. Something like this:
// should be from a file but this is just an example
string[] lines = {
"00XXXXXXXXXX01YYYYYYYYYY02XXXXXXXXX.XXXXXXXXX.XXXXXXXXX.XXXXXXXXX.XXXXXXXXXX",
"00XXXXXXXXXX01YYYYYYYYYY02XXXXXXXXX.XXXXXXXXX.XXXXXXXXX.XXXXXXXXX.XXXXXXXXXX01YYYYYYYYYY02XXXXXXXXX.XXXXXXXXX.XXXXXXXXX.XXXXXXXXX.XXXXXXXXXX",
"00XXXXXXXXXX01YYYYYYYYYY02XXXXXXXXX.XXXXXXXXX.XXXXXXXXX.XXXXXXXXX.XXXXXXXXXX",
"00XXXXXXXXXX01YYYYYYYYYY02XXXXXXXXX.XXXXXXXXX.XXXXXXXXX.XXXXXXXXX.XXXXXXXXXX",
"00XXXXXXXXXX01YYYYYYYYYY02XXXXXXXXX.XXXXXXXXX.XXXXXXXXX.XXXXXXXXX.XXXXXXXXXX",
};
// loop through each line
// (lines can have multiple items)
foreach (string line in lines)
{
Client client = Parser.ParseData (line);
Console.WriteLine ("Read: " + client.name);
}
Contents of Sample.txt:
00Company1 0115522 02This is a description for company 1. 00Company2 0115523 02This is a description for company 2. 00Company3 0115524 02This is a description for company 3
Note that in the code below, the fields are 2 characters longer than those specified in the original question. This is because I am including the headings in the length of each field, thus a field of a length of 10is effectively 12 by including the 00 from the heading. If this is undesirable, tweak the offsets of the entries in the fieldLengths array.
String directory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
String file = "Sample.txt";
String path = Path.Combine(directory, file);
Int32[] fieldLengths = new Int32[] { 12, 12, 52 };
List<RowData> rows = new List<RowData>();
Byte[] buffer = new Byte[fieldLengths.Sum()];
using (var stream = File.OpenRead(path))
{
while (stream.Read(buffer, 0, buffer.Length) > 0)
{
List<String> fieldValues = new List<String>();
Int32 offset = 0;
for (int i = 0; i < fieldLengths.Length; i++)
{
var value = Encoding.UTF8.GetString(buffer, offset, fieldLengths[i]);
fieldValues.Add(value);
offset += fieldLengths[i];
}
String companyName = fieldValues[0];
String itemNumber = fieldValues[1];
String description = fieldValues[2];
var row = new RowData(companyName, itemNumber, description);
rows.Add(row);
}
}
Class definition for RowData:
public class RowData
{
public String Company { get; set; }
public String Number { get; set; }
public String Description { get; set; }
public RowData(String company, String number, String description)
{
Company = company;
Number = number;
Description = description;
}
}
The results will be in the rows variable.
You would have to split rows based on a delimiter. It would seem that in your case you are using whitespace as a delimiter.
The method you are looking for is String.Split(), it should cover your needs :) Documentation is located at https://msdn.microsoft.com/en-us/library/system.string.split(v=vs.110).aspx - It also includes examples.
I'd do something like this:
string myLineOfText = "MyCompany 12345 The description of my company";
string[] partsOfMyLine = myLineOfText.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
Best of luck! :)
I am making a program in c# that will take in a list of names and scores from a text document, get the score on its own and then find the highest of the scores. I can separate the name from the score when it is just one but as soon as I try make it an array I do not have any idea what I am doing.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
System.IO.File.Exists(#"U:\StudentExamMarks.txt");
string[] text = System.IO.File.ReadAllLines(#"U:\StudentExamMarks.txt");
int a = 0;
string[] results = new string[a];
for(int i=0;i<text.Length ; i++ )
{
int x = text[i].LastIndexOf("\t");
int y = text[i].Length;
int z = (y - (x + 1));
results[a] = text[i].Substring((x+1), (z));
a++;
Console.WriteLine("{0}", results);
}
}
}
This is what I have so far
the list is as follows
John Cross 100
Christina Chandler 105
Greg Hamilton 107
Pearl Becker 111
Angel Ford 115
Wendell Sparks 118
like I said when I attempted it without an array I can get it to display the 100 from the first result. I also do not know how when I find the largest result how to link it back to the students name.
I suggest to use a class to hold all properties, that improves readability a lot:
public class StudentExam
{
public string StudentName { get; set; }
public int Mark { get; set; }
}
and following to read all lines and to fill a List<StudentExam>:
var lines = File.ReadLines(#"U:\StudentExamMarks.txt")
.Where(l => !String.IsNullOrWhiteSpace(l));
List<StudentExam> studentsMarks = new List<StudentExam>();
foreach (string line in lines)
{
string[] tokens = line.Split('\t');
string markToken = tokens.Last().Trim();
int mark;
if (tokens.Length > 1 && int.TryParse(markToken, out mark))
{
StudentExam exam = new StudentExam{
Mark = mark,
StudentName = String.Join(" ", tokens.Take(tokens.Length - 1)).Trim()
};
studentsMarks.Add(exam);
}
}
Now it's easy to get the max-mark:
int maxMark = studentsMarks.Max(sm => sm.Mark); // 118
To find the highest score, you can use Linq with Regex like this
var lines = new[] {
"John Cross 100",
"Christina Chandler 105",
"Greg Hamilton 107",
"Pearl Becker 111"
};
var maxScore = lines.Max(l => int.Parse(Regex.Match(l, #"\b\d+\b").Value));
Here, I'm assuming you have read the file correctly into lines and all of them has a valid int value of the score.
If the end of each entry is always a space followed by the student's score, you can use a simple substring:
int max = text.Max(x => Convert.ToInt32(x.Substring(x.LastIndexOf(' '))));
For each entry, create a substring that starts at the last index of ' ' and then convert that to an integer. Then return the max of those values.
I am trying to figure out how to solve the error as stated in the title, which occurs on the bold line within this snippet:
while (textIn.Peek() != -1)
{
string row = textIn.ReadLine();
string[] columns = row.Split('|');
StudentClass studentList = new StudentClass();
studentList.Name = columns[0];
**studentList.Scores = columns[1];**
students.Add(studentList);
}
The previous line of code loads the names just fine since it is not a List within the class I have created, but "Scores" is within a list, however. What modifications would I need to do? These values are supposed to be displayed within a textbox from a text file upon loading the application.
Here is the class in which "Scores" is in (I have highlighted it):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyNameSpace
{
//set the class to public
public class StudentClass
{
public StudentClass()
{
this.Scores = new List<int>();
}
public StudentClass (string Name, List<int> Scores)
{
this.Name = Name;
this.Scores = Scores;
}
public string Name
{ get;
set;
}
//initializes the scores
**public List<int> Scores
{ get;
set;
}**
public override string ToString()
{
string names = this.Name;
foreach (int myScore in Scores)
{ names += "|" + myScore.ToString();
}
return names;
}
public int GetScoreTotal()
{
int sum = 0;
foreach (int score in Scores)
{ sum += score;
}
return sum;
}
public int GetScoreCount()
{ return Scores.Count;
}
public void addScore(int Score)
{
Scores.Add(Score);
}
}
}
You can't just assign a string containing a sequence of numbers to a property of type List<int>.
You need to split the string into seperate numbers, then parse these substrings to get the integers they represent.
E.g.
var text = "1 2 3 4 5 6";
var numerals = text.Split(' ');
var numbers = numerals.Select(x => int.Parse(x)).ToList();
I.e. in your code replace:
studentList.Scores = columns[1];
with:
studentList.Scores = columns[1].Split(' ').Select(int.Parse).ToList();
(Or your own multi-line, more readable/debugable equivalent.)
You'll need to modify the parameter passed to Split() according to how the scores are formatted in your column.
You'll also need to add using System.Linq; at the top if you don't already have it.
As far as the question goes, how would the compiler ever know how to convert the string to a list, when there could be so many string representations of a list. If it was to do this it would be an incredibly slow operation.
Fix
To fix your code you could replace your loop with this.
while (textIn.Peek() != -1)
{
string row = textIn.ReadLine();
StudentClass studentList = new StudentClass();
int index = row.IndexOf("|");
//checking that there were some scores
if (index < 0) {
studentList.Name = row;
continue;
}
studentList.Name = row.Substring(0, index);
studentList.Scores = row.Substring(index + 1).Split('|').Select(int.Parse).ToList();
students.Add(studentList);
}
There are however a number of problems even with this fix.
For one if you were to add another list delimited by '|' it would become increasingly hard for you to parse using this kind of approach.
I suggest instead that you look at serializing your class(es) with something a little more powerful and generic like Json.Net.
Hope this helps.