Как мне сгенерировать поток из строки?

603

Мне нужно написать unit test для метода, который берет поток, который поступает из текстового файла. Я хотел бы сделать что-то вроде этого:

Stream s = GenerateStreamFromString("a,b \n c,d");
Теги:
string
unit-testing
stream

12 ответов

778
Лучший ответ
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 (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?

  • 116
    Важно отметить, что поток состоит из байтов, а строка состоит из символов. Важно понимать, что преобразование символа в один или несколько байтов (или в поток, как в этом случае) всегда использует (или предполагает) определенную кодировку. Этот ответ, хотя и является правильным в некоторых случаях, использует кодировку по умолчанию и может вообще не подходить. Явная передача Encoding конструктору StreamWriter сделает более очевидным, что автору необходимо учитывать последствия Encoding.
  • 4
    Вы говорите «Не забудьте использовать Using» для использования потока, но в вашем методе GenerateStreamFromString вы не используете Using с StreamWriter. Для этого есть причина?
Показать ещё 7 комментариев
609

Другое решение:

public static MemoryStream GenerateStreamFromString(string value)
{
    return new MemoryStream(Encoding.UTF8.GetBytes(value ?? ""));
}
  • 30
    На всякий случай, если кто-то использует это с десериализацией строки XML, мне пришлось переключить UTF8 на Unicode, чтобы он работал без флага. Отличный пост !!!
  • 1
    Мне нравится этот (с твиком Rhyous и дополнительным дополнительным сахаром для использования в качестве метода расширения) лучше, чем принятый ответ; более гибкий, меньше LOC и меньше вовлеченных объектов (нет явной необходимости в StreamWriter)
Показать ещё 3 комментария
103

Добавьте это в статический класс классов:

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
}
  • 5
    Я обнаружил, что возвращаемый поток закрывается (вызывая полуслучайные исключения), когда сборщик мусора очищает StreamWriter . Исправление состояло в том, чтобы использовать другой конструктор - тот, который позволял мне указывать оставлять открытыми .
33
public Stream GenerateStreamFromString(string s)
{
    return new MemoryStream(Encoding.UTF8.GetBytes(s));
}
19

Используйте класс MemoryStream, вызывая Encoding.GetBytes, чтобы сначала преобразовать вашу строку в массив байтов.

Вам понадобится TextReader в потоке? Если это так, вы можете напрямую передать StringReader и обходить шаги MemoryStream и Encoding.

11

Я использовал сочетание ответов вроде этого:

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....
}
  • 0
    Томас, почему проголосовали? enc = enc ?? Encoding.UTF8 позволяет мне специально запрашивать поток с определенной кодировкой или значением по умолчанию UTF8, и потому что в .net (насколько я использую это .net 4.0) вы не можете дать ссылочный тип, кроме строки, значение по умолчанию в функции подпись эта строка необходима, имеет ли это смысл?
  • 0
    упоминание о том, что вам нужно поместить это в отдельный класс (не универсальный статический класс?), также полезно и уменьшает количество голосов.
9

Здесь вы идете:

private Stream GenerateStreamFromString(String p)
{
    Byte[] bytes = UTF8Encoding.GetBytes(p);
    MemoryStream strm = new MemoryStream();
    strm.Write(bytes, 0, bytes.Length);
    return strm;
}
  • 1
    Позиция должна быть сброшена после записи. Лучше использовать конструктор, как в ответе joelnet.
8

Я думаю, вы можете воспользоваться MemoryStream. Вы можете заполнить его строковыми байтами, которые вы получите, используя метод GetBytes Класс кодирования.

7

Мы используем методы расширения, перечисленные ниже. Я думаю, вы должны заставить разработчика принять решение о кодировании, поэтому есть меньше магии.

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 ?? ""));
    }
}
  • 0
    Я бы предпочел реализовать первый метод в качестве return ToStream(s, Encoding.UTF8); , В текущей реализации ( return s.ToStream(Encoding.UTF8); разработчик вынужден усерднее думать, чтобы понять код, и кажется, что случай s == null не NullReferenceException и выдает NullReferenceException .
0

Немного измененная версия методов расширения, предложенная в комментарии ответа @JoelNet и ответа @Shaun Bowe. Потому что я согласен с комментарием @Palec.

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));
-1

Хорошая комбинация расширений строк:

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;
}
-1
/// <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));
}
  • 2
    System.String всегда в UTF-16. Не так ли?
  • 3
    Вы говорите: «Для работы не нужно знать строковое кодирование». Это все равно, что сказать, что не имеет значения, какого цвета твоя машина, потому что ты собираешься залить зеленую краску. Как указывает абатищев, вы, по неизвестному принципу, используете кодировку UTF-16 для преобразования строки в байты. Допустим, теперь вы записываете содержимое этого потока в файл и открываете его как текстовый файл. Вы увидите пробелы между каждым персонажем.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню