2010-04-13 19 views
28

Quiero escribir un String en un Stream (un MemoryStream en este caso) y leer los bytes uno por uno.Escribir String to Stream y leerlo de nuevo no funciona

stringAsStream = new MemoryStream(); 
UnicodeEncoding uniEncoding = new UnicodeEncoding(); 
String message = "Message"; 

stringAsStream.Write(uniEncoding.GetBytes(message), 0, message.Length); 

Console.WriteLine("This:\t\t" + (char)uniEncoding.GetBytes(message)[0]); 
Console.WriteLine("Differs from:\t" + (char)stringAsStream.ReadByte()); 

El (no deseado) resultado que obtengo es:

This:   M 
Differs from: ? 

Se ve como que no está siendo leído correctamente, ya que el primer carácter de "mensaje" es 'M', que funciona cuando obtener los bytes de la instancia de UnicodeEncoding pero no al leerlos de la transmisión.

¿Qué estoy haciendo mal?


El cuadro más grande: Tengo un algoritmo que trabajará en los bytes de una corriente, me gustaría ser lo más general posible y trabajar con cualquier corriente. Me gustaría convertir un ASCII-String en un MemoryStream, o tal vez usar otro método para poder trabajar en el String como un Stream. El algoritmo en cuestión funcionará en los bytes de Stream.

+3

¿Desea leer los bytes o los caracteres uno por uno de la secuencia? Tenga en cuenta que byte! = Char ya que su codificación es Unicode. –

+0

Sí, lo hago. Y byte será char ya que leeré documentos ASCII. ¿Sería mejor utilizar algo que no sea uniEncoding en mi caso? – Deleted

+0

Agregué una imagen más grande según lo solicitado. – Deleted

Respuesta

47

Después de escribir en MemoryStream y antes de volver a leerlo, necesita Seek volver al principio de MemoryStream para no leer desde el final.

ACTUALIZACIÓN

Después de ver su actualización, creo que hay una manera más fiable para construir la corriente:

UnicodeEncoding uniEncoding = new UnicodeEncoding(); 
String message = "Message"; 

// You might not want to use the outer using statement that I have 
// I wasn't sure how long you would need the MemoryStream object  
using(MemoryStream ms = new MemoryStream()) 
{ 
    var sw = new StreamWriter(ms, uniEncoding); 
    try 
    { 
     sw.Write(message); 
     sw.Flush();//otherwise you are risking empty stream 
     ms.Seek(0, SeekOrigin.Begin); 

     // Test and work with the stream here. 
     // If you need to start back at the beginning, be sure to Seek again. 
    } 
    finally 
    { 
     sw.Dispose(); 
    } 
} 

Como se puede ver, este código utiliza un StreamWriter para escribir toda la cadena (con la codificación adecuada) al MemoryStream. Esto elimina la molestia de garantizar que se escribe toda la matriz de bytes para la cadena.

Actualización: Entré en el problema con la secuencia vacía varias veces. Es suficiente llamar al Flush justo después de que haya terminado de escribir.

+9

Ese código fallará en 'ms.Seek (0, SeekOrigin.Begin)', porque poner un uso en StreamWriter cerrará su flujo, que en este caso es el MemoryStream. Luego, cuando intentes buscar, te dará una excepción 'No se puede acceder a un Stream cerrado '. –

+0

Puede utilizar este enfoque si ajusta la secuencia en una clase que anula la eliminación de la secuencia subyacente. [Esta respuesta] (http://stackoverflow.com/questions/4465824/is-it-okay-to-not-close-streamreader-streamwriter-to-keep-the-underlying-stream-o/4466519#4466519) a una pregunta relacionada apunta a [una implementación] (http://csharptest.net/browse/src/Library/IO/NonClosingStream.cs). –

+3

Como se indicó, este código no se compila. La respuesta de Joel Purra es de una sola línea y funciona mucho mejor. – Slaggg

13

Estás usando message.Length que devuelve el número de caracteres en la cadena, pero que debería estar utilizando la nubmer de bytes a leer. Usted debe usar algo como:

byte[] messageBytes = uniEncoding.GetBytes(message); 
stringAsStream.Write(messageBytes, 0, messageBytes.Length); 

Estás entonces la lectura de un solo byte y esperando conseguir un personaje del que acaba echando a char. UnicodeEncoding usará dos bytes por carácter.

Como Justin dice que usted es también que no está buscando de nuevo al principio de la corriente.

Básicamente me temo que casi todo está mal aquí. Por favor dénos la imagen más grande y podemos ayudarlo a resolver lo que debería realmente estar haciendo. Usar un StreamWriter para escribir y luego un StreamReader para leer es posiblemente lo que quieras, pero realmente no podemos decir solo por el breve código que has mostrado.

+0

Después de escribir en un MemoryStream, ¿no es necesario que vuelva al principio para comenzar a leer nuevamente? –

+0

@Justin: Sí, ese es otro problema :) –

+0

He agregado una imagen más grande según lo solicitado. Quizás es más fácil entender lo que quiero hacer ahora. – Deleted

1

es necesario restablecer el flujo al principio:

stringAsStream.Seek(0, SeekOrigin.Begin); 
Console.WriteLine("Differs from:\t" + (char)stringAsStream.ReadByte()); 

Esto también se puede hacer mediante el establecimiento de la Position propiedad a 0:

stringAsStream.Position = 0 
4

creo que sería mucho más productivo para usar un TextWriter, en este caso un StreamWriter para escribir en el MemoryStream. Después de eso, como han dicho otros, debe "rebobinar" el MemoryStream usando algo como stringAsStream.Position = 0L;.

stringAsStream = new MemoryStream(); 

// create stream writer with UTF-16 (Unicode) encoding to write to the memory stream 
using(StreamWriter sWriter = new StreamWriter(stringAsStream, UnicodeEncoding.Unicode)) 
{ 
    sWriter.Write("Lorem ipsum."); 
} 
stringAsStream.Position = 0L; // rewind 

Tenga en cuenta que:

StreamWriter forma predeterminada a usar una instancia de UTF8Encoding menos que se especifique lo contrario. Esta instancia de UTF8Encoding se construye sin una marca de orden de bytes (BOM)

También, usted no tiene que crear un new UnicodeEncoding() por lo general, ya que no hay ya uno como un miembro estático de la clase para su uso en la práctica utf-8, utf-16 y utf-32 sabores.

Y luego, finalmente (como han dicho otros) está tratando de convertir el byte s directamente en char s, que no lo son. Si tuviera un flujo de memoria y supiera que era una cadena, usaría un TextReader para recuperar la cadena de los bytes. Me parece "peligroso" perder el tiempo con los bytes en bruto.

+0

Mi objetivo principal es trabajar con Streams. Como trabajaré en los bytes de texto ASCII y archivos binarios. – Deleted

+0

Ah, ya veo. En ese caso, supongo que tendrás que meterse con ellos. ;) –

31

Pruebe este "one-liner" de Delta's Blog, String To MemoryStream (C#).

MemoryStream stringInMemoryStream = 
    new MemoryStream(ASCIIEncoding.Default.GetBytes("Your string here")); 

La cadena se cargarán en la MemoryStream, y se puede leer de él. Consulte Encoding.GetBytes(...), que también ha sido implemented for a few other encodings.

+0

Y para recuperar los datos, ['Encoding.ASCII.GetString (ms.ToArray());'] (http://stackoverflow.com/a/234262/). –

+3

Recomiendo encarecidamente a cualquiera que use este ejemplo que use Encoding.UTF8 sobre ASCII, o cualquier otra codificación de ámbito más amplio. Es probable que cualquier texto escrito por gente que no sea {american, english, ...} rinda mal en ASCII. – Cornelius