StreamReader ReadLine() returns 空字符串,没有添加到列表
StreamReader ReadLine() returns empty string, nothing added to list
我在从文件读取到列表时遇到一些问题。
文件内容是这样的:
[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]
方法如下所示:
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;
}
它读取第一行没问题,但是 directions = ReadLine()
returns 绝对没有,也没有任何内容添加到列表中 - 它不应该跳到下一行并分配给 directions
?.整个结果是 WhosebugException
.
if with in While 得到满足然后读取下一个不满足第一个 if 条件的字符
阅读完 ]
字符后,您认为该行已完成阅读并认为 directions = reader.ReadLine();
会让您 that way this way no way all the way
但是,您还没有读完该行,因为在 ]
之后有 "newline" 字符,而您的 reader 确实读取了该行,并且 returns 是一个空字符串.
我已经将你的方法重构为
public static List<Room> ReadRooms(string path)
{
List<Room> rooms = new List<Room>();
string roomName=String.Empty;
StringBuilder directionsBuilder= new StringBuilder();
using (StreamReader reader = new StreamReader(path))
{
while (!reader.EndOfStream)
{
string line = reader.ReadLine();
if (line != null && line.StartsWith("[END]"))
{
rooms.Add(new Room(roomName, directionsBuilder.ToString()));
directionsBuilder.Clear();
}
else if (line != null && line.StartsWith("["))
roomName = line.Substring(1, line.Length - 2);
else
directionsBuilder.AppendLine(line);
}
}
return rooms;
}
它应该处理多行方向以及房间名称,如 ROOM102 或 APARTMENT201 等
您提到的具体问题是因为您一次读取一个字符,当您看到 ]
时,您会执行 ReadLine
,但这只会读取到换行符在 ]
之后,而不是您想要的下一行。但是,即使您修复了代码中存在的其他问题(例如未清除 StringBuilder
),最好只处理行而不是一次读取一个字符。此外,除了使用需要清理的 StreamReader
之外,您还可以使用方便的 File.ReadLine
方法。
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;
}
我列出了一些潜在的错误案例,您需要决定如何处理。
我在从文件读取到列表时遇到一些问题。 文件内容是这样的:
[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]
方法如下所示:
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;
}
它读取第一行没问题,但是 directions = ReadLine()
returns 绝对没有,也没有任何内容添加到列表中 - 它不应该跳到下一行并分配给 directions
?.整个结果是 WhosebugException
.
if with in While 得到满足然后读取下一个不满足第一个 if 条件的字符
阅读完 ]
字符后,您认为该行已完成阅读并认为 directions = reader.ReadLine();
会让您 that way this way no way all the way
但是,您还没有读完该行,因为在 ]
之后有 "newline" 字符,而您的 reader 确实读取了该行,并且 returns 是一个空字符串.
我已经将你的方法重构为
public static List<Room> ReadRooms(string path)
{
List<Room> rooms = new List<Room>();
string roomName=String.Empty;
StringBuilder directionsBuilder= new StringBuilder();
using (StreamReader reader = new StreamReader(path))
{
while (!reader.EndOfStream)
{
string line = reader.ReadLine();
if (line != null && line.StartsWith("[END]"))
{
rooms.Add(new Room(roomName, directionsBuilder.ToString()));
directionsBuilder.Clear();
}
else if (line != null && line.StartsWith("["))
roomName = line.Substring(1, line.Length - 2);
else
directionsBuilder.AppendLine(line);
}
}
return rooms;
}
它应该处理多行方向以及房间名称,如 ROOM102 或 APARTMENT201 等
您提到的具体问题是因为您一次读取一个字符,当您看到 ]
时,您会执行 ReadLine
,但这只会读取到换行符在 ]
之后,而不是您想要的下一行。但是,即使您修复了代码中存在的其他问题(例如未清除 StringBuilder
),最好只处理行而不是一次读取一个字符。此外,除了使用需要清理的 StreamReader
之外,您还可以使用方便的 File.ReadLine
方法。
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;
}
我列出了一些潜在的错误案例,您需要决定如何处理。