2009-06-28 10 views
6

¿Alguien sabe dónde puedo encontrar una implementación del divisor de Stream?¿Cómo puedo dividir (copiar) una transmisión en .NET?

Estoy buscando tomar una secuencia, y obtener dos secuencias separadas que se pueden leer y cerrar de forma independiente sin afectarse mutuamente. Estas secuencias deberían devolver los mismos datos binarios que la secuencia original. No es necesario implementar Posición o Buscar y tal ... Reenviar solo.

Preferiría si no solo copiara toda la secuencia en la memoria y la sirviera varias veces, lo cual sería bastante simple de implementar por mi cuenta.

¿Hay algo que pueda hacer esto?

+1

algo como 'tee' en UNIX ... –

+0

Es probable que tenga que ser en torno a un buffer circular. Trataré de escribir una implementación rápida si tengo tiempo. – Noldorin

Respuesta

4

No fuera de la caja.

Deberá almacenar en búfer los datos de la secuencia original de una manera FIFO, descartando solo los datos que han sido leídos por todas las secuencias de "lector".

que haría uso:

"gestión" objeto
  • Un sosteniendo una especie de cola de byte [] la celebración de los trozos para ser amortiguadas y la lectura de los datos adicionales de la corriente de la fuente si es necesario
  • Algunos " lector "instancias que saben dónde y en qué memoria intermedia están leyendo, y que solicitan el siguiente fragmento de la" gestión "y lo notifican cuando ya no usan un fragmento, para que pueda ser eliminado de la cola
1

No creo que pueda encontrar una implementación genérica para hacer justamente eso. Una secuencia es bastante abstracta, no se sabe de dónde provienen los bytes. Por ejemplo, no sabes si apoyará la búsqueda; y usted no sabe el costo relativo de las operaciones. (¡The Stream podría ser una abstracción de la lectura de datos de un servidor remoto, o incluso de una cinta de respaldo!).

Si puede tener un MemoryStream y almacenar el contenido una vez, puede crear dos flujos separados usando el mismo búfer; y se comportarán como Streams independientes pero solo usarán el recuerdo una vez.

De lo contrario, creo que lo mejor es crear una clase contenedora que almacene los bytes leídos de una secuencia, hasta que también sean leídos por la segunda secuencia. Eso le daría el comportamiento deseado solo de reenvío, pero en el peor de los casos, podría correr el riesgo de almacenar todos los bytes en la memoria, si la segunda secuencia no se lee hasta que la primera secuencia haya terminado de leer todo el contenido.

+0

¿Cuál es la aplicación de esto? – headsling

1

No se puede hacer esto sin duplicar al menos parte del flujo de sourse, principalmente debido a que si no suena como que se puede controlar la velocidad a la que se consumen (¿múltiples hilos?). Podrías hacer algo inteligente con respecto a una lectura del otro (y por lo tanto hacer la copia solo en ese punto) pero la complejidad de esto parece que no vale la pena.

+0

sin mencionar que si se utiliza en un escenario de múltiples hilos, se evita que el sistema operativo o la plataforma utilicen sus propios mecanismos intrínsecos para tener múltiples lectores del mismo archivo. Si se usa en la memoria, el peor de los casos será que tendrá que copiar toda la secuencia de todos modos así que probar algo como esto posiblemente requiera un gran esfuerzo para observar ... ¿podría funcionar mejor un modelo push to multiple consumers? – ShuggyCoUk

3

Esto podría ser complicado sin arriesgar el mantenimiento de todo almacenado en la memoria (si las transmisiones están en BOF y EOF respectivamente).

Me pregunto si no es más fácil escribir la corriente en el disco, copiarlo, y tienen dos corrientes de lectura desde el disco, con la auto-borrado incorporada en el Close() (es decir, escribir sus propios Stream envoltura alrededor de FileStream).

0

Con la introducción de asíncrono/esperan, siempre y cuando todas las tareas de lectura, salvo una, son asincrónicas, debe poder procesar los mismos datos dos veces con solo un hilo del sistema operativo.

Lo que creo que quiere, es una lista vinculada de los bloques de datos que ha visto hasta ahora. Luego puede tener múltiples instancias Stream personalizadas que contengan un puntero en esta lista. A medida que los bloques caen al final de la lista, serán recolectados como basura. Reutilizar la memoria inmediatamente requeriría algún otro tipo de lista circular y recuento de referencias. Factible, pero más complicado.

Cuando su Stream personalizado puede responder una llamada de Lectura rápida desde el caché, copie los datos, avance el puntero hacia abajo en la lista y vuelva.

Cuando su Stream ha alcanzado el final de la lista de caché, desea emitir una sola ReadAsync a la secuencia subyacente, sin esperarla, y almacenar en caché la tarea devuelta con el bloque de datos. Entonces, si cualquier otro lector de Stream también se da cuenta y trata de leer más antes de que se complete esta lectura, puede devolver el mismo objeto de Tarea.

De esta manera, ambos lectores engancharán su continuación al resultado de la misma llamada de ReadAsync. Cuando regresa la lectura única, ambas tareas de lectura ejecutarán secuencialmente el siguiente paso de su proceso.

0

He hecho un SplitStream disponible en github y NuGet.

Funciona así.

using (var inputSplitStream = new ReadableSplitStream(inputSourceStream)) 

using (var inputFileStream = inputSplitStream.GetForwardReadOnlyStream()) 
using (var outputFileStream = File.OpenWrite("MyFileOnAnyFilestore.bin")) 

using (var inputSha1Stream = inputSplitStream.GetForwardReadOnlyStream()) 
using (var outputSha1Stream = SHA1.Create()) 
{ 
    inputSplitStream.StartReadAhead(); 

    Parallel.Invoke(
     () => { 
      var bytes = outputSha1Stream.ComputeHash(inputSha1Stream); 
      var checksumSha1 = string.Join("", bytes.Select(x => x.ToString("x"))); 
     }, 
     () => { 
      inputFileStream.CopyTo(outputFileStream); 
     }, 
    ); 
} 

No lo he probado en transmisiones muy grandes, pero inténtelo.

github: https://github.com/microknights/SplitStream

+0

Respuestas sin el código real no es útil o deseable en Stack Overflow. Una buena respuesta SO será totalmente independiente, en lugar de depender por completo de algún recurso externo como es el caso aquí. Edite su respuesta para que los lectores puedan obtener toda la información importante de la publicación de respuesta en sí. –

Cuestiones relacionadas