Import Text Files Into A List In C#

Suppose you have to import the text file into the C# list. Your text file has a columns header in the first line. It looks like this one,

ID;FirstName;Surname
1;John;Smith
2;Max;McDonald

Your import function should be able to import any desired format. Firstly you need to create a data class like this,

class Person {
    public int ID {
        get;
        set;
    }
    public string FirstName {
        get;
        set;
    }
    public string Surname {
        get;
        set;
    }
}

Secondly, you need to create a generic function to import a text file.

The function should have two parameters, fileName and column separator, and return generic list.

static List<T> ImportFile<T>(string FileName, char ColumnSeperator)

At the beginning of the function, we should create an instance List<T>.

Now we need to open the text file. For this example, we can use the function File.OpenText. But remember to surround it by using the statement (StreamReader supports IDisposable interface).

Now we need to read the column headers in the first row.

var columnsHeader = str.ReadLine().Split(ColumnSeperator);

Now we need to create a while statement to read the next line of text.

string s;
while ((s = str.ReadLine()) != null) {}

We can create an object T type if we make a constraint on a generic function where T : new().

We will update the properties of the T object using a reflection.

We use typeof(T) to get a reflection-type object. This object is the main reflection type and we can access properties, fields, constructors, methods. 

Now we can get the property by calling GetProperty on reflection type object. If the property info object is null, it can't write or it is an indexer, we will ignore it.

We store properties info in the list for the future.

One of our properties is an integer type, so we need to check PropertyType and if it is necessary we convert the string into an integer. To set a value of the property, we call the SetProperty function on the property info object. 

In the end, we add an object to the return list.

And finally, we add exception handling.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
namespace ImportTextFile {
    class Person {
        public int ID {
            get;
            set;
        }
        public string FirstName {
            get;
            set;
        }
        public string Surname {
            get;
            set;
        }
    }
    [Serializable]
    class ImportTextFileException: Exception {
        public int Line {
            get;
            private set;
        }
        public int Column {
            get;
            private set;
        }
        public ImportTextFileException(): base() {}
        public ImportTextFileException(string message): base(message) {}
        public ImportTextFileException(string message, Exception innerException, int Line, int Column): base(string.Format("Error in line {0} column {1}. {2}", Line, Column, message), innerException) {
            this.Line = Line;
            this.Column = Column;
        }
        protected ImportTextFileException(SerializationInfo info, StreamingContext context): base(info, context) {
            this.Line = info.GetInt32("Line");
            this.Column = info.GetInt32("Column");
        }
        public override void GetObjectData(SerializationInfo info, StreamingContext context) {
            base.GetObjectData(info, context);
            info.AddValue("Line", this.Line);
            info.AddValue("Column", this.Column);
        }
    }
    class Program {
        static void Main(string[] args) {
            var list = ImportFile < Person > ("persons.txt", ';');
        }
        static List < T > ImportFile < T > (string FileName, char ColumnSeperator) where T: new() {
            var list = new List < T > ();
            using(var str = File.OpenText(FileName)) {
                int Line = 1;
                int Column = 0;
                try {
                    var columnsHeader = str.ReadLine().Split(ColumnSeperator);
                    var t = typeof(T);
                    var plist = new Dictionary < int,
                        PropertyInfo > ();
                    for (int i = 0; i < columnsHeader.Length; i++) {
                        var p = t.GetProperty(columnsHeader[i]);
                        if (p != null && p.CanWrite && p.GetIndexParameters().Length == 0) plist.Add(i, p);
                    }
                    string s;
                    while ((s = str.ReadLine()) != null) {
                        Line++;
                        var data = s.Split(ColumnSeperator);
                        var obj = new T();
                        foreach(var p in plist) {
                            Column = p.Key;
                            if (p.Value.PropertyType == typeof(int)) p.Value.SetValue(obj, int.Parse(data[Column]), null);
                            else if (p.Value.PropertyType == typeof(string)) p.Value.SetValue(obj, data[Column], null);
                        }
                        list.Add(obj);
                    }
                    return list;
                } catch (Exception ex) {
                    throw new ImportTextFileException(ex.Message, ex, Line, Column + 1);
                }
            }
        }
    }
}