2012-07-17 15 views
9

En mi programa, básicamente estoy leyendo en un archivo, procesándolo y volviéndolo al programa principal como un flujo de memoria, que será procesado por un lector de flujo. Todo esto será manejado por una clase al lado de mi principal.MemoryStream desactiva la lectura cuando se devuelve

El problema es que cuando devuelvo la secuencia de memoria de mi método en otra clase, la variable "canread" se establece en false y, por lo tanto, falla la inicialización del lector de secuencias.

A continuación se muestra un ejemplo del problema que sucede (aunque aquí estoy escribiendo a la MemoryStream en la otra clase, pero todavía hace que el mismo error cuando pase de nuevo.

En la clase llamada " OtherClass ":

public static MemoryStream ImportantStreamManipulator() 
{ 
    MemoryStream MemStream = new MemoryStream(); 

    StreamWriter writer = new StreamWriter(MemStream); 
    using (writer) 
    { 
     //Code that writes stuff to the memorystream via streamwriter 

     return MemStream; 
    } 
} 

la función llama en el programa principal:

MemoryStream MStream = Otherclass.ImportantStreamManipulator(); 
StreamReader reader = new StreamReader(MStream); 

Cuando pongo un punto de interrupción en la "vuelta MemStream", la "propiedad CanRead" sigue siendo establecido en verdadero. Una vez que paso tal que vuelve a mi función principal, y escribe el valor devuelto a MStream, la propiedad "CanRead" se establece en falso. Esto causa una excepción en StreamReader diciendo que MStream no se pudo leer (como la propiedad indicada). Los datos están en el buffer de secuencias como debería ser, pero simplemente no puedo sacarlos.

¿Cómo lo configuro para que "CanRead" informe verdadero una vez que se devuelve a mi main? ¿O no entiendo cómo funciona MemoryStream y cómo lograré lo que quiero hacer?

Respuesta

21

Este es el problema:

using (writer) 
{ 
    //Code that writes stuff to the memorystream via streamwriter 

    return MemStream; 
} 

que estás cerrando el escritor, que cierra la MemoryStream. En este caso, no desea hacer eso ... aunque necesita vaciar el escritor, y rebobinar el MemoryStream. Sólo cambia el código para:

public static MemoryStream ImportantStreamManipulator() 
{ 
    // Probably add a comment here stating that the lack of using statements 
    // is deliberate. 
    MemoryStream stream = new MemoryStream(); 

    StreamWriter writer = new StreamWriter(stream); 
    // Code that writes stuff to the memorystream via streamwriter 

    writer.Flush(); 
    stream.Position = 0; 
    return stream; 
} 
+0

Jon, ¿qué sucede si 'writer' se pasa por GC antes de que se use' stream'? –

+2

@KevinBrock: Entonces solo se recolecta basura, y se pierde cualquier dato almacenado. 'StreamWriter' no tiene un finalizador, AFAIK. –

+0

Eso fue exactamente. Pensé que devolverlo enviaría una versión no cerrada antes de que el uso descarte el streamwriter. Creo que estaba pensando que la devolución devolvería una copia del MemoryStream, no una referencia por algún motivo.También pensé que abandonar el método ImportantStreamManipulator a través de una devolución eliminaría automáticamente el generador de secuencias de todos modos, así que no estaba seguro de que esto fuera posible. ¿El eliminador de secuencias se eliminará más adelante en el programa a través del GC, o solo se eliminará una vez que elimine el MemoryStream o cierre el programa? – Xantham

0

Como otros han dicho, el problema es que la corriente se cierra cuando el StreamWriter está cerrado. Una forma posible de lidiar con esto es devolver una matriz de bytes en lugar de un MemoryStream. Esto evita tener objetos potencialmente de larga ejecución que deben ser eliminados por el recolector de basura.

public static void Main() 
{ 
    OutputData(GetData()); 
} 

public static byte[] GetData() 
{ 
    byte[] binaryData = null; 

    using (MemoryStream ms = new MemoryStream()) 
    using (StreamWriter sw = new StreamWriter(ms)) 
    { 
     string data = "My test data is really great!"; 

     sw.Write(data); 
     sw.Flush(); 

     binaryData = ms.ToArray(); 
    } 

    return binaryData; 
} 

public static void OutputData(byte[] binaryData) 
{ 
    using (MemoryStream ms = new MemoryStream(binaryData)) 
    using (StreamReader sr = new StreamReader(ms)) 
    { 
     Console.WriteLine(sr.ReadToEnd()); 
    } 
} 

Otro método es copiar el flujo a otra secuencia antes de volver. Sin embargo, esto todavía tiene el problema de que el acceso posterior a él con un StreamReader cerrará esa secuencia.

public static void RunSnippet() 
{ 
    OutputData(GetData()); 
} 

public static MemoryStream GetData() 
{ 
    MemoryStream outputStream = new MemoryStream(); 

    using (MemoryStream ms = new MemoryStream()) 
    using (StreamWriter sw = new StreamWriter(ms)) 
    { 
     string data = "My test data is really great!"; 

     sw.Write(data); 
     sw.Flush(); 

     ms.WriteTo(outputStream); 
     outputStream.Seek(0, SeekOrigin.Begin); 
    } 

    return outputStream; 
} 

public static void OutputData(MemoryStream inputStream) 
{ 
    using (StreamReader sr = new StreamReader(inputStream)) 
    { 
     Console.WriteLine(sr.ReadToEnd()); 
    } 
} 
Cuestiones relacionadas