2009-06-10 13 views
8

He estado jugando con lo que pensé que era una idea simple. Quiero poder leer en un archivo desde algún lugar (sitio web, sistema de archivos, ftp), realizar algunas operaciones en él (comprimir, encriptar, etc.) y luego guardarlo en algún lugar (en algún lugar puede ser un sistema de archivos, ftp o lo que sea) . Es un diseño básico de tubería. Lo que me gustaría hacer es leer en el archivo y ponerlo en un MemoryStream, luego realizar las operaciones en los datos en el MemoryStream, y luego guardar esos datos en el MemoryStream en algún lugar. Estaba pensando que podría utilizar el mismo flujo de hacer esto, pero correr en un par de problemas:Stream Reuse en C#

  1. Cada vez que utilice un StreamWriter o StreamReader que necesito para cerrarla y que cierra la corriente de modo que no puedo usarlo nunca más . Parece que debe haber alguna manera de evitar eso.
  2. Algunos de estos archivos pueden ser grandes y me quedo sin memoria si trato de leer todo al mismo tiempo.

Estaba esperando poder girar cada uno de los pasos como subprocesos separados y hacer que el paso de compresión comience tan pronto como haya datos en la transmisión, y tan pronto como la compresión tenga algunos datos comprimidos disponibles en la transmisión, podría comenzar a guardarlo (por ejemplo). ¿Hay algo como esto fácilmente posible con las transmisiones C#? ¿ALguien tiene pensamientos sobre cómo lograr esto mejor?

Gracias,

Mike

Respuesta

4

Utilizando un método de ayuda para conducir la transmisión:

static public void StreamCopy(Stream source, Stream target) 
{ 
    byte[] buffer = new byte[8 * 1024]; 

    int size; 
    do 
    { 
     size = source.Read(buffer, 0, 8 * 1024); 
     target.Write(buffer, 0, size); 
    } while (size > 0); 
} 

Se pueden combinar fácilmente lo que necesita:

using (FileStream iFile = new FileStream(...)) 
using (FileStream oFile = new FileStream(...)) 
using (DeflateStream oZip = new DeflateStream(outFile, CompressionMode.Compress)) 
    StreamCopy(iFile, oZip); 

Dependiendo de lo que en realidad están tratando de hacer, encadenarías las transmisiones de manera diferente. Esto también usa relativamente poca memoria, porque solo los datos que se operan están en la memoria.

+0

Desde .NET 4.0, puede utilizar el incorporado '.CopyTo' y'.CopyToAsync' para copiar una secuencia a otra –

1

StreamReader/StreamWriter no deberían han sido diseñados para cerrar su transmisión subyacente - eso es una horrible falla en el BCL. Pero lo hacen, no se cambiarán (debido a la compatibilidad con versiones anteriores), por lo que estamos atascados con este desastre de una API.

Pero hay algunas soluciones bien establecidas, si desea utilizar StreamReader/Writer pero mantenga la corriente abierta después.

  • Para un StreamReader: no Eliminar el StreamReader. Es así de simple. Es inofensivo dejar un StreamReader sin llamar a Dispose. El único efecto es que tu Stream no se cerrará prematuramente, lo que en realidad es un plus.
  • Para un StreamWriter: puede haber datos almacenados en el búfer, por lo que no puede salirse con la suya simplemente dejándolo ir. Debe llamar a Flush para asegurarse de que los datos almacenados en el búfer se escriban en el flujo. Luego puede dejar que el StreamWriter se vaya. (. Básicamente, se pone una escalera donde normalmente se le ha puesto un Desechar)
+2

Si REALMENTE necesita usar StreamReader y StreamWriter, pero DEBE asegurarse de que la secuencia subyacente nunca se cierra, cree una clase proxy Stream que simplemente pase cada llamada a la transmisión subyacente, excepto las llamadas al Cerrar y Descarte los métodos (que ignoraría) y ajuste el flujo subyacente con el proxy al pasarlo a los constructores de Reader/Writer. Luego puede usar clases de Lector/Escritor normalmente. –