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
.
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.