ReadAllLines для объекта Stream?
Существует File.ReadAllLines
, но не Stream.ReadAllLines
.
using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Test_Resources.Resources.Accounts.txt"))
using (StreamReader reader = new StreamReader(stream))
{
// Would prefer string[] result = reader.ReadAllLines();
string result = reader.ReadToEnd();
}
Есть ли способ сделать это или мне нужно вручную прокручивать файл по строкам?
Ответы
Ответ 1
Вы можете написать метод, который читается по строкам, например:
public IEnumerable<string> ReadLines(Func<Stream> streamProvider,
Encoding encoding)
{
using (var stream = streamProvider())
using (var reader = new StreamReader(stream, encoding))
{
string line;
while ((line = reader.ReadLine()) != null)
{
yield return line;
}
}
}
Затем назовите его как:
var lines = ReadLines(() => Assembly.GetExecutingAssembly()
.GetManifestResourceStream(resourceName),
Encoding.UTF8)
.ToList();
Часть Func<>
должна справляться при чтении более одного раза и избегать ненужных потоков. Конечно, вы можете легко обернуть этот код в методе.
Если вам не нужно все сразу в памяти, вам даже не понадобится ToList
...
Ответ 2
Свойство .EndOfStream
может использоваться в цикле вместо проверки того, не следующая ли следующая строка.
List<string> lines = new List<string>();
using (StreamReader reader = new StreamReader("example.txt"))
{
while(!reader.EndOfStream)
{
lines.Add(reader.ReadLine());
}
}
Ответ 3
using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Test_Resources.Resources.Accounts.txt"))
using (StreamReader reader = new StreamReader(stream))
{
// Would prefer string[] result = reader.ReadAllLines();
string[] result = reader.ReadToEnd().Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
}
Ответ 4
Использование Split
здесь:
reader
.ReadToEnd()
.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
не эквивалентен ReadLine
. Если вы посмотрите на источник ReadLine
, StreamReader.cs, вы увидите, что он обрабатывает терминаторы строк:\r,\n и \r\n правильно. ReadLine
не возвращает лишнюю пустую строку, когда терминатор строки \r\n, что типично для DOS/Windows. Split
"видит" (анализирует)\r, за которым следует \n как два отдельных разделителя и возвращает пустую строку.
'StringSplitOptions.RemoveEmptyEntries' в приведенном выше коде удаляет эти пустые строки, но также удаляет любые пустые строки, которые также появляются на входе.
Таким образом, для ввода line1\г \р line3\г
ReadLine
возвращает 3 строки. Второй пуст.
Split
создает 4 строки. (После последней \r. Есть дополнительная строка). Затем он удаляет 2-й и 4-й.
Обратите внимание, что Split
не подходит для разбора текстовых строк, которые являются "пост-исправными". То есть разделитель появляется после токена. Пока Split
подходит для инфикса, где между токенами появляются разделители. Это разница между a, b, c и line1\r, line2, line3\r. Для этих входов Split
возвращает 3 строки или 4 строки соответственно.
Ответ 5
Если вы хотите использовать StreamReader, тогда да, вам нужно будет использовать ReadLine и цикл через StreamReader, считая строку за строкой.
Что-то вроде этого:
string line;
using (StreamReader reader = new StreamReader(stream))
{
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
}
или попробуйте
using (StreamReader reader = new StreamReader("file.txt"))
{
string[] content = reader.ReadToEnd().Replace("\n","").Split('\t');
}
Ответ 6
Используя следующий метод расширения:
public static class Extensions
{
public static IEnumerable<string> ReadAllLines(this StreamReader reader)
{
string line;
while ((line = reader.ReadLine()) != null)
{
yield return line;
}
}
}
Можно получить нужный код:
using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Test_Resources.Resources.Accounts.txt"))
using (StreamReader reader = new StreamReader(stream))
{
string[] result = reader.ReadAllLines().ToArray();
}