Как мне сгенерировать поток из строки?
Мне нужно написать модульный тест для метода, который принимает поток из текстового файла. Я хотел бы сделать что-то вроде этого:
Stream s = GenerateStreamFromString("a,b \n c,d");
16 ответов
public static Stream GenerateStreamFromString(string s)
{
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
writer.Write(s);
writer.Flush();
stream.Position = 0;
return stream;
}
Не забудьте использовать Using:
using (var stream = GenerateStreamFromString("a,b \n c,d"))
{
// ... Do stuff to stream
}
О StreamWriter
не утилизировать. StreamWriter
это просто обертка вокруг базового потока и не использует ресурсы, которые должны быть удалены. Dispose
метод закроет базовый Stream
тот StreamWriter
пишет в. В этом случае это MemoryStream
мы хотим вернуться.
В.NET 4.5 теперь есть перегрузка для StreamWriter
он сохраняет основной поток открытым после удаления средства записи, но этот код делает то же самое и работает с другими версиями.NET.
См. Есть ли способ закрыть StreamWriter, не закрывая его BaseStream?
Другое решение:
public static MemoryStream GenerateStreamFromString(string value)
{
return new MemoryStream(Encoding.UTF8.GetBytes(value ?? ""));
}
Добавьте это в служебный класс статической строки:
public static Stream ToStream(this string str)
{
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(str);
writer.Flush();
stream.Position = 0;
return stream;
}
Это добавляет функцию расширения, так что вы можете просто:
using (var stringStream = "My string".ToStream())
{
// use stringStream
}
public Stream GenerateStreamFromString(string s)
{
return new MemoryStream(Encoding.UTF8.GetBytes(s));
}
Слегка измененная версия методов расширения, предложенная в комментарии к ответу @JoelNet и ответу @Shaun Bowe. Потому что я согласен с комментарием @ Палека.
public static Stream ToStream(this string value) => ToStream(value, Encoding.UTF8);
public static Stream ToStream(this string value, Encoding encoding) => new MemoryStream(encoding.GetBytes(value ?? string.Empty));
Я использовал смесь ответов, как это:
public static Stream ToStream(this string str, Encoding enc = null)
{
enc = enc ?? Encoding.UTF8;
return new MemoryStream(enc.GetBytes(str ?? ""));
}
И тогда я использую это так:
String someStr="This is a Test";
Encoding enc = getEncodingFromSomeWhere();
using (Stream stream = someStr.ToStream(enc))
{
// Do something with the stream....
}
Использовать MemoryStream
класс, зовет Encoding.GetBytes
сначала превратить вашу строку в массив байтов.
Вам впоследствии нужна TextReader
в потоке? Если это так, вы могли бы поставить StringReader
напрямую и в обход MemoryStream
а также Encoding
шаги.
Мы используем методы расширения, перечисленные ниже. Я думаю, что вы должны сделать так, чтобы разработчик принял решение о кодировке, чтобы не было никакой магии.
public static class StringExtensions {
public static Stream ToStream(this string s) {
return s.ToStream(Encoding.UTF8);
}
public static Stream ToStream(this string s, Encoding encoding) {
return new MemoryStream(encoding.GetBytes(s ?? ""));
}
}
Если вам нужно изменить кодировку, я голосую за решение @ShaunBowe. Но каждый ответ здесь копирует всю строку в памяти хотя бы один раз. Ответы с ToCharArray
+ BlockCopy
сделать это дважды.
Если это имеет значение здесь просто Stream
обертка для необработанной нити UTF-16. Если используется с StreamReader
Выбрать Encoding.Unicode
для этого:
public class StringStream : Stream
{
private readonly string str;
public override bool CanRead => true;
public override bool CanSeek => true;
public override bool CanWrite => false;
public override long Length => str.Length * 2;
public override long Position { get; set; } // TODO: bounds check
public StringStream(string s) => str = s ?? throw new ArgumentNullException(nameof(s));
public override long Seek(long offset, SeekOrigin origin)
{
switch (origin)
{
case SeekOrigin.Begin:
Position = offset;
break;
case SeekOrigin.Current:
Position += offset;
break;
case SeekOrigin.End:
Position = Length - offset;
break;
}
return Position;
}
private byte this[int i] => (i & 1) == 0 ? (byte)(str[i / 2] & 0xFF) : (byte)(str[i / 2] >> 8);
public override int Read(byte[] buffer, int offset, int count)
{
// TODO: bounds check
var len = Math.Min(count, Length - Position);
for (int i = 0; i < len; i++)
buffer[offset++] = this[(int)(Position++)];
return (int)len;
}
public override int ReadByte() => Position >= Length ? -1 : this[(int)Position++];
public override void Flush() { }
public override void SetLength(long value) => throw new NotSupportedException();
public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();
public override string ToString() => str; // ;)
}
А вот более полное решение с необходимыми проверками привязки (получено из MemoryStream
так оно и есть ToArray
а также WriteTo
методы тоже).
Ну вот:
private Stream GenerateStreamFromString(String p)
{
Byte[] bytes = UTF8Encoding.GetBytes(p);
MemoryStream strm = new MemoryStream();
strm.Write(bytes, 0, bytes.Length);
return strm;
}
Я думаю, что вы можете извлечь выгоду из использования MemoryStream. Вы можете заполнить его строковыми байтами, которые вы получите, используя метод GetBytes класса Encoding.
Теперь с C# 11 мы можем сделать это в одну строку:
var ms = new MemoryStream("some string"u8.ToArray());
Подробности о строковых литералах Utf8 можно найти здесь https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-11.0/utf8-string-literals#detailed-design
Буквально существует тип StreamReader, который делает все это за вас. Используйте это, возможно, этого не существовало, когда изначально задавали этот вопрос, я не знаю.
Но сегодня используйте StreamReader.
https://docs.microsoft.com/en-us/dotnet/api/system.io.streamreader?view=net-5.0
Stream stream = ToStream(""); //passing your string input.
public static Stream ToStream(string str)
{
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(str);
writer.Flush();
stream.Position = 0;
return stream;
}
/// <summary>
/// Get Byte[] from String
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static byte[] GetBytes(string str)
{
byte[] bytes = new byte[str.Length * sizeof(char)];
System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
/// <summary>
/// Get Stream from String
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static Stream GetStream(string str)
{
return new MemoryStream(GetBytes(str));
}
Хорошая комбинация расширений String:
public static byte[] GetBytes(this string str)
{
byte[] bytes = new byte[str.Length * sizeof(char)];
System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
public static Stream ToStream(this string str)
{
Stream StringStream = new MemoryStream();
StringStream.Read(str.GetBytes(), 0, str.Length);
return StringStream;
}