kalka79
kalka79

Reputation: 31

C# reading a string from text file, splitting and putting into tabstring

I got stuck writing some simple program which writes some data to the text file and reads them form this file later.

I have a function that writes lines to a txt file; each line contains Name, Surname, and Idnumber.

And below I have a function that reads the data from that file.

I want to separate Name, Surname and Idnumber so below code seems to be correct but during debugging I got a message "An unhandled exception of type 'System.NullReferenceException' occurred" for this line: string[] tabstring = myString.Split(' ', ' ');.

I created the tab string which contains 3 elements - each for each word in the line i.e. tabstring[0]=Name and so on.

The while loop is to do it for each line in the text file. But something is wrong.

public void ReadFromFile()
        {
           FileStream fsListOfObjects = new FileStream("C:\\Users\\Dom\\Desktop\\ListOfObjects.txt", 
           FileMode.Open);
            StreamReader srListOfObjects = new StreamReader(fsListOfObjects);

            while (srListOfObjects.ReadLine() != null)
            {
                string myString= (srListOfObjects.ReadLine();
                Console.WriteLine(myString);
                **string[] tabstring = myString.Split(' ', ' ');**

                Name = tabstring[0];
                Surname = tabstring[1];
                Id= long.Parse(tabstring[2]);
                ClassName object= new ClassName(Name, Surname, Id);
                myList.Add(object);
            }
            srListOfObjects.Close();

            Console.ReadLine();
        }

And here is what the text file looks like:

Ann Brown 1233456789
Bruce Willis 098987875
Bill Gates 789678678

and so on...

I would appreciate your comments on the described problem.

Upvotes: 1

Views: 1832

Answers (3)

Andrew Morton
Andrew Morton

Reputation: 25023

while (srListOfObjects.ReadLine().. reads a line but doesn't save it into a variable. string myString= (srListOfObjects.ReadLine()) reads another line.

Use while (!srListOfObjects.EndOfStream) to check for the end of the stream: StreamReader.EndOfStream Property.

Also, it is a good idea to check that the correct number of parts of the string were obtained by the Split - it guards against things like lines with only whitespace.

Things like StreamReaders need have .Dispose() called on them to clear up "unmanaged resources" - an easy way to do that which will work even if the program crashes is to use the using statement.

If you make the ReadFromFile method into a function instead of a void then you can avoid (no pun) using a global variable for the data. Global variables are not necessarily a problem, but it's usually good to avoid them.

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

namespace ConsoleApp1
{

    public class ClassName
    {
        public string Name { get; set; }
        public string Surname { get; set; }
        public long Id { get; set; }

    }

    class Program
    {
        public static List<ClassName> ReadFromFile(string fileName)
        {
            var result = new List<ClassName>();

            using (var sr = new StreamReader(fileName))
            {
                while (!sr.EndOfStream)
                {
                    string line = sr.ReadLine();
                    var parts = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                    if (parts.Count() == 3)
                    {
                        result.Add(new ClassName
                        {
                            Name = parts[0],
                            Surname = parts[1],
                            Id = long.Parse(parts[2])
                        });
                    }
                }
            }

            return result;

        }

        static void Main(string[] args)
        {
            string myFile = @"C:\temp\namesList.txt";
            var theList = ReadFromFile(myFile);

            foreach(var c in theList)
            {
                Console.WriteLine($"{c.Id} - {c.Surname}, {c.Name}");
            }

            Console.ReadLine();

        }
    }
}

outputs:

1233456789 - Brown, Ann
98987875 - Willis, Bruce
789678678 - Gates, Bill

Upvotes: 2

InBetween
InBetween

Reputation: 32760

Your problem is here:

while (srListOfObjects.ReadLine() != null)
{
    string myString= (srListOfObjects.ReadLine();

You are entering the loop on the condition that srListOfObjects.ReadLine() returns something other than null but then you are immediately reading a new line form srListOfObjects and storing the returned reference in myString. This has obviously two problems:

  1. The second call to ReadLine can return null and you are not checking if it is. The error you are getting is due to this reason.
  2. You are losing information. You are ignoring the line you are reading when checking the while condition. Until your program crashes or runs to the end (depends on wether the input file has even or odd number of lines), you will process only half of the data.

Update: You should only read one line per iteration. One way to do it is declaring and initializing myString before entering the loop and updating it on every iteration:

var myString = srListOfObjects.ReadLine();

while (myString != null)
{
    //do your stuff
    myString = srListOfObjects.ReadLine();
}

Upvotes: 0

Darkwing
Darkwing

Reputation: 7585

https://learn.microsoft.com/en-us/dotnet/api/system.io.streamreader.readline?view=netcore-3.1

ReadLine() - Reads a line of characters from the current stream and returns the data as a string.

In your code you do a null check, but then call ReadLine again. When you hit the last line, you will get a NULL string, and splitting that will fail with the NULL ref

Upvotes: 0

Related Questions