Я написал специальный XML-ридер, потому что мне нужно что-то, что не будет читаться заранее из исходного потока. Я хотел, чтобы объект мог читать свои данные из потока, не оказывая негативного влияния на поток для родительского объекта. Таким образом, поток может быть передан по дереву объектов.
Это минимальная реализация, предназначенная только для целей проекта, который ее использует (прямо сейчас). Работает достаточно хорошо, за исключением одного метода - ReadString
. Этот метод используется для чтения содержимого текущего элемента в виде строки, останавливаясь при достижении конечного элемента. Это определяется путем подсчета уровней вложенности. Между тем, он читает из потока, символ за символом, добавляя StringBuilder для полученной строки.
Для элемента коллекции это может занять много времени. Я уверен, что многое можно сделать, чтобы лучше это реализовать, так что именно здесь начинается мое непрерывное образование. Я мог бы действительно использовать некоторую помощь / руководство. Некоторые примечания о методах, которые он вызывает:
Read
- возвращает следующий байт в потоке или -1.
ReadUntilChar
- вызывает Read
до тех пор, пока не будет достигнут указанный символ или -1, добавляя строку с помощью StringBuilder.
Без лишних слов, вот моя двуногая черепаха. Константы были заменены фактическими значениями.
public string ReadString() {
int level = 0;
long originalPosition = m_stream.Position;
StringBuilder sb = new StringBuilder();
sbyte read;
try {
// We are already within the element that contains the string.
// Read until we reach an end element when the level == 0.
// We want to leave the reader positioned at the end element.
do {
sb.Append(ReadUntilChar('<'));
if((read = Read()) == '/') {
// End element
if(level == 0) {
// End element for the element in context, the string is complete.
// Replace the two bytes of the end element read.
m_stream.Seek(-2, System.IO.SeekOrigin.Current);
break;
} else {
// End element for a child element.
// Add the two bytes read to the resulting string and continue.
sb.Append('<');
sb.Append('/');
level--;
}
} else {
// Start element
level++;
sb.Append('<');
sb.Append((char)read);
}
} while(read != -1);
return sb.ToString().Trim();
} catch {
// Return to the original position that we started at.
m_stream.Seek(originalPosition - m_stream.Position, System.IO.SeekOrigin.Current);
throw;
}
}