Search code examples
c#listfilestreamreader

StreamReader ReadLine() returns empty string, nothing added to list


I have a few problems reading from a file to a list. The file content is like this:

[ROOM101]
that way this way no way all the way
[END]
[ROOM102]
all the way that way this way no way
[END]
[ROOM103]
no way all the way that way this way
[END]

And the method looks like this:

public static List<Room> ReadRooms(string path)
{
    List<Room> rooms = new List<Room>();
    StreamReader reader = new StreamReader(path);
    bool roomsLeft = true;
    char currentChar;
    string directions;
    StringBuilder builder = new StringBuilder();

    while (roomsLeft) {
        currentChar = (char)reader.Read();
        if (currentChar == '[') {
            currentChar = (char)reader.Read();
            while (currentChar != ']') {
                builder.Append(currentChar);
                currentChar = (char)reader.Read();
            }
            if (builder.ToString() != "END") {
                directions = reader.ReadLine();
                rooms.Add(new Room(builder.ToString(), directions));
            }
        }
        if (reader.EndOfStream) {
            roomsLeft = false;
        }
    }
    reader.Close();

    return rooms;
}

It reads the first line fine, but directions = ReadLine() returns absolutely nothing, and nothing gets added to the list - shouldn't it jump to the next line and assign to directions?. The whole thing results in a StackOverflowException.


Solution

  • The specific issue you are referring to is because you read one character at at time and when you see the ] you then do a ReadLine, but that will just read upto the newline that is after the ] instead of the next line which is what you want. But even if you fix that there are other issues in your code (like not clearing the StringBuilder) and it's better to just deal with lines instead of reading one character at a time. Additionally instead of using a StreamReader that you need to clean up you can just use the handy File.ReadLine method.

    public static List<Room> ReadRooms(string path)
    {
        List<Room> rooms = new List<Room>();
        bool inRoom = false;
        StringBuilder directions = new StringBuilder();
        string name = null;
        foreach (var line in File.ReadLines(path))
        {
            if (inRoom)
            {
                if(line == "[END]")
                {
                    rooms.Add(new Room(name, directions.ToString()));
                    inRoom = false;
                    directions.Clear();
                }
                else if (line.StartsWith("[") && line.EndsWith("]"))
                {
                    // Found a start before the end, condiser throwing an 
                    // exception, ignoring, or keep it as part of the directions.
                }
                else
                {
                    directions.AppendLine(line);
                }
            }
            else
            { 
                if(line == "[END]")
                {
                    // Found an end before a start either throw an exception or
                    // just ignore this.
                }
                else if (line.StartsWith("[") && line.EndsWith("]"))
                {
                    inRoom = true;
                    name = line.Trim('[', ']');
                }
                else
                {
                    // Consider throwing an exception here or just ignoring lines 
                    // between [END] and the next room.
                }
            }
        }
    
        if (inRoom)
        {
            // Determine what to do if you had a room start, but no [END]
        }
    
        return rooms;
    }
    

    I've include a number of potential error cases that you'll need to decide how to handle.