¿Cómo genero una secuencia a partir de una cadena?

Necesito escribir una prueba unitaria para un método que toma una secuencia que proviene de un archivo de texto. Me gustaría hacer algo como esto:

Stream s = GenerateStreamFromString("a,b \n c,d");

preguntado el 10 de diciembre de 09 a las 05:12

Para una solución de ahorro de memoria, consulte StringReaderStream in stackoverflow.com/a/55170901/254109 -

12 Respuestas

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;
}

No olvide usar el uso de:

using (var stream = GenerateStreamFromString("a,b \n c,d"))
{
    // ... Do stuff to stream
}

Acerca de StreamWriter no ser desechado. StreamWriter es solo una envoltura alrededor del flujo base y no usa ningún recurso que deba eliminarse. La Dispose El método cerrará el subyacente Stream que StreamWriter está escribiendo a. En este caso ese es el MemoryStream queremos volver.

En .NET 4.5 ahora hay una sobrecarga para StreamWriter que mantiene abierta la secuencia subyacente después de eliminar el escritor, pero este código hace lo mismo y también funciona con otras versiones de .NET.

Ver ¿Hay alguna forma de cerrar StreamWriter sin cerrar su BaseStream?

Respondido 14 Feb 18, 19:02

Un concepto importante a destacar es que una secuencia se compone de bytes, mientras que una cadena se compone de caracteres. Es fundamental comprender que convertir un carácter en uno o más bytes (o en un Stream como en este caso) siempre usa (o asume) una codificación particular. Esta respuesta, aunque correcta en algunos casos, utiliza la codificación predeterminada y puede que no sea adecuada en general. Pasar explícitamente una codificación al constructor StreamWriter haría más evidente que el autor debe considerar las implicaciones de la codificación. - drwatsoncode

Dices "No olvides usar el uso" para usar la transmisión, pero en tu GenerateStreamFromString método que no está utilizando con el StreamWriter. ¿Hay alguna razón para esto? - paquet

@ Ben Sí. Si desecha StreamWriter, la transmisión subyacente también se cerrará. No queremos eso. La única razón por la que Writer es desechable es para limpiar el flujo, por lo que es seguro ignorarlo. - cameron macfarland

También debe tenerse en cuenta que la cadena completa se copia en una memoria, lo que puede ser importante para cadenas grandes porque ahora tenemos una copia adicional en la memoria. - UGEEN

@ahong No realmente. StreamWriter probablemente esté haciendo lo que dijiste internamente de todos modos. La ventaja es la encapsulación y el código más simple, pero a costa de abstraer cosas como la codificación. Depende de lo que intente lograr. - cameron macfarland

Otra solución:

public static MemoryStream GenerateStreamFromString(string value)
{
    return new MemoryStream(Encoding.UTF8.GetBytes(value ?? ""));
}

Respondido 26 Oct 16, 20:10

En caso de que alguien use esto con una deserialización de cadena XML, tuve que cambiar UTF8 a Unicode para que funcione sin una bandera. ¡¡¡Buena publicación!!! - gaspa79

Me gusta este (con el ajuste de Rhyous y el azúcar extra trivial para usar como método de extensión) mejor que la respuesta aceptada; más flexible, menos LOC y menos objetos involucrados (sin necesidad explícita de un StreamWriter) - keiths

new MemoryStream(Encoding.UTF8.GetBytes("\ufeff" + (value ?? "")) si necesita incluir la lista de materiales al comienzo de la transmisión, robert4

Esta es una sintaxis muy compacta pero causará muchas asignaciones de bytes [], así que tenga cuidado con el código de alto rendimiento. - michael.aird

Esta solución aún dejaba la oportunidad de hacer que la transmisión fuera de solo lectura. new MemoryStream( value, false ). No puede hacer que una transmisión sea de solo lectura si tiene que escribirla con un escritor de transmisión. - codigokandis

Agregue esto a una clase de utilidad de cadena estática:

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;
}

Esto agrega una función de extensión para que pueda simplemente:

using (var stringStream = "My string".ToStream())
{
    // use stringStream
}

respondido 18 nov., 15:14

Descubrí que el flujo devuelto se cierra (causando excepciones semi-aleatorias) cuando el recolector de basura limpia el StreamWriter. La solución fue usar un constructor diferente, uno que me permitiera especificar dejar abierto. - Bevan

public Stream GenerateStreamFromString(string s)
{
    return new MemoryStream(Encoding.UTF8.GetBytes(s));
}

Respondido el 03 de enero de 14 a las 18:01

Use el MemoryStream clase, llamando Encoding.GetBytes para convertir su cadena en una matriz de bytes primero.

¿Necesita posteriormente un TextReader en la corriente? Si es así, puede proporcionar un StringReader directamente, y eludir el MemoryStream y Encoding pasos.

Respondido el 10 de diciembre de 09 a las 08:12

Usé una combinación de respuestas como esta:

public static Stream ToStream(this string str, Encoding enc = null)
{
    enc = enc ?? Encoding.UTF8;
    return new MemoryStream(enc.GetBytes(str ?? ""));
}

Y luego lo uso así:

String someStr="This is a Test";
Encoding enc = getEncodingFromSomeWhere();
using (Stream stream = someStr.ToStream(enc))
{
    // Do something with the stream....
}

Respondido 22 Oct 17, 23:10

Thomas, ¿por qué votar en contra? enc = enc ?? Encoding.UTF8 me permite preguntar específicamente a la transmisión con una codificación específica, o un valor predeterminado de UTF8, y porque en .net (en la medida en que lo uso .net 4.0) no se puede dar un tipo de referencia que no sea una cadena de un valor predeterminado en la función firma esta línea es necesaria, ¿tiene sentido? - Robocide

mencionar que necesita poner esto en una clase separada (¿clase estática no genérica?) También es útil y reduce los votos negativos. - Ali

Versión modernizada y ligeramente modificada de los métodos de extensión para ToStream:

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

Modificación como se sugiere en el comentario de @ Palec de la respuesta de @Shaun Bowe.

Respondido el 14 de enero de 19 a las 10:01

Usamos los métodos de extensión que se enumeran a continuación. Creo que debería hacer que el desarrollador tome una decisión sobre la codificación, para que haya menos magia involucrada.

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 ?? ""));
    }
}

Respondido 22 Oct 17, 23:10

Preferiría implementar el primer método como return ToStream(s, Encoding.UTF8);. En la implementación actual (return s.ToStream(Encoding.UTF8);, el desarrollador se ve obligado a pensar más para comprender el código y parece que el caso de s == null no se maneja y lanza NullReferenceException. - Dedo

Aqui tienes:

private Stream GenerateStreamFromString(String p)
{
    Byte[] bytes = UTF8Encoding.GetBytes(p);
    MemoryStream strm = new MemoryStream();
    strm.Write(bytes, 0, bytes.Length);
    return strm;
}

Respondido el 10 de diciembre de 09 a las 08:12

La posición debe restablecerse después de escribir. Es mejor usar el constructor, como en la respuesta de joelnet. - jim balter

Creo que puede beneficiarse del uso de un Flujo de memoria. Puede completarlo con los bytes de cadena que obtiene utilizando el ObtenerBytes método de la Clase de codificación.

Respondido el 10 de diciembre de 09 a las 08:12

Si necesitas cambiar la codificación, voto por @ShaunBowela solución. Pero cada respuesta aquí copia toda la cadena en la memoria al menos una vez. Las respuestas con ToCharArray + BlockCopy combo hazlo dos veces.

Si eso importa aquí es un simple Stream envoltorio para la cadena UTF-16 sin procesar. Si se usa con un StreamReader seleccione Encoding.Unicode para ello:

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; // ;)     
}

Y aquí es una solución más completa con los controles encuadernados necesarios (derivados de MemoryStream así que tiene ToArray y WriteTo métodos también).

Respondido 18 Jul 19, 19:07

Una buena combinación de extensiones 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;
}

Respondido 22 Oct 17, 23:10

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.