¿Qué es un flujo?

Respuestas:

161

Una secuencia representa una secuencia de objetos (generalmente bytes, pero no necesariamente), a los que se puede acceder en orden secuencial. Operaciones típicas en una secuencia:

  • leer un byte La próxima vez que lea, obtendrá el siguiente byte, y así sucesivamente.
  • leer varios bytes de la secuencia en una matriz
  • buscar (mover su posición actual en la secuencia, de modo que la próxima vez que lea obtenga bytes de la nueva posición)
  • escribe un byte
  • escribir varios bytes de una matriz en la secuencia
  • omite bytes de la secuencia (esto es como leer, pero ignora los datos. O si lo prefiere, es como buscar pero solo puede avanzar).
  • empuje los bytes hacia atrás en una secuencia de entrada (esto es como "deshacer" para la lectura; empuja unos pocos bytes hacia atrás en la secuencia, de modo que la próxima vez que lea eso es lo que verá. En ocasiones es útil para los analizadores, como es:
  • vistazo (mira los bytes sin leerlos, de modo que todavía estén allí en la secuencia para leerlos más tarde)

Una secuencia en particular puede admitir lectura (en cuyo caso es una "secuencia de entrada"), escritura ("secuencia de salida") o ambas. No todas las transmisiones son buscables.

El retroceso es bastante raro, pero siempre puede agregarlo a una secuencia envolviendo la secuencia de entrada real en otra secuencia de entrada que contiene un búfer interno. Las lecturas provienen del búfer, y si retrocede, los datos se colocan en el búfer. Si no hay nada en el búfer, la secuencia de retroceso se lee de la secuencia real. Este es un ejemplo simple de un "adaptador de flujo": se encuentra en el "extremo" de un flujo de entrada, es un flujo de entrada en sí mismo y hace algo adicional que el flujo original no hizo.

Stream es una abstracción útil porque puede describir archivos (que en realidad son matrices, por lo tanto, la búsqueda es sencilla) pero también la entrada / salida de terminal (que no se puede buscar a menos que esté almacenada), sockets, puertos serie, etc. Para que pueda escribir código que diga o "Quiero algunos datos, y no me importa de dónde provienen o cómo llegaron aquí", o "Produciré algunos datos, y depende de mi persona que llama lo que le sucede". El primero toma un parámetro de flujo de entrada, el segundo toma un parámetro de flujo de salida.

La mejor analogía que se me ocurre es que una corriente es una cinta transportadora que se dirige hacia usted o se aleja de usted (o, a veces, ambas). Sacas cosas de un flujo de entrada, pones cosas en un flujo de salida. Algunos transportadores se pueden considerar como que salen de un agujero en la pared; no son buscables, leer o escribir es un trato único. Algunos transportadores se colocan frente a usted, y usted puede moverse eligiendo el paradero en la secuencia que desea leer / escribir, eso es lo que busca.

Sin embargo, como dice IRBMe, es mejor pensar en una secuencia en términos de las operaciones que ofrece (que varían de implementación en implementación, pero tienen mucho en común) en lugar de una analogía física. Las transmisiones son "cosas que puedes leer o escribir". Cuando comience a conectar adaptadores de flujo, puede pensar en ellos como una caja con un transportador dentro y un transportador fuera, que se conecta a otros flujos y luego el cuadro realiza alguna transformación en los datos (comprimirlos o cambiar los avances de línea UNIX) a DOS, o lo que sea). Las tuberías son otra prueba exhaustiva de la metáfora: ahí es donde creas un par de transmisiones de modo que todo lo que escribes en una se pueda leer de la otra. Piensa en los agujeros de gusano :-)

Steve Jessop
fuente
3
Con mucho, la mejor explicación que he leído. Junto con lo que dice en SICP ("El procesamiento de flujo nos permite modelar sistemas que tienen estado sin usar asignación o datos mutables"), creo que finalmente lo entiendo. ¡Gracias!
Kyle Chadha
85

Una transmisión ya es una metáfora, una analogía, por lo que realmente no hay necesidad de proporcionar otra. Se puede considerar básicamente como una tubería con un flujo de agua en el que el agua es en realidad datos y la tubería es la corriente. Supongo que es una especie de tubería de 2 vías si la corriente es bidireccional. Básicamente es una abstracción común que se coloca sobre cosas donde hay un flujo o secuencia de datos en una o ambas direcciones.

En lenguajes como C #, VB.Net, C ++, Java, etc., la metáfora de flujo se usa para muchas cosas. Hay secuencias de archivos, en las que abre un archivo y puede leer desde la secuencia o escribir en ella continuamente; Hay flujos de red en los que leer y escribir en el flujo lee y escribe en una conexión de red establecida subyacente. Las secuencias para escribir solo se denominan secuencias de salida, como en este ejemplo, y de manera similar, las secuencias que son solo para lectura se denominan secuencias de entrada, como en este ejemplo.

Un flujo puede realizar la transformación o la codificación de datos (un SslStream en .Net, por ejemplo, se comerá los datos de negociación SSL y se los ocultará; un TelnetStream podría ocultarle las negociaciones de Telnet, pero le proporcionará acceso a los datos; A ZipOutputStream en Java le permite escribir en archivos en un archivo zip sin tener que preocuparse por las partes internas del formato de archivo zip.

Otra cosa común que puede encontrar son las secuencias de texto que le permiten escribir cadenas en lugar de bytes, o algunos idiomas proporcionan secuencias binarias que le permiten escribir tipos primitivos. Una cosa común que encontrará en las secuencias de texto es una codificación de caracteres, que debe tener en cuenta.

Algunas transmisiones también admiten acceso aleatorio, como en este ejemplo. Una transmisión de red, por otro lado, por razones obvias, no lo haría.

  • MSDN ofrece una buena visión general de las transmisiones en .Net.
  • Sun también tiene una visión general de su clase general OutputStream y la clase InputStream .
  • En C ++, aquí está la documentación de istream (flujo de entrada), ostream (flujo de salida) y iostream (flujo bidireccional).

Los sistemas operativos similares a UNIX también admiten el modelo de flujo con entrada y salida del programa, como se describe aquí .

IRBMe
fuente
13

Las respuestas dadas hasta ahora son excelentes. Solo proporciono otro para resaltar que una secuencia no es una secuencia de bytes o específica de un lenguaje de programación ya que el concepto es universal (mientras que su implementación puede ser única). A menudo veo una gran cantidad de explicaciones en línea en términos de SQL, C o Java, que tienen sentido ya que un flujo de archivos trata con ubicaciones de memoria y operaciones de bajo nivel. Pero a menudo abordan cómo crear un flujo de archivos y operar en el archivo potencial en su idioma dado en lugar de discutir el concepto de flujo.

La metáfora

Como se mencionó, a streames una metáfora, una abstracción de algo más complejo. Para que tu imaginación funcione, ofrezco algunas otras metáforas:

  1. quieres llenar una piscina vacía con agua. Una forma de lograr esto es conectar una manguera a una espita, colocando el extremo de la manguera en la piscina y abriendo el agua.

la manguera es la corriente

  1. Del mismo modo, si quisiera rellenar su automóvil con gasolina, iría a una bomba de gasolina, insertaría la boquilla en su tanque de gasolina y abriría la válvula apretando la palanca de bloqueo.

la manguera, la boquilla y los mecanismos asociados para permitir que el gas fluya hacia su tanque es la corriente

  1. si necesita ir a trabajar, comenzará a conducir desde su casa hasta la oficina usando la autopista.

la autopista es la corriente

  1. Si quieres tener una conversación con alguien, usarías tus oídos para escuchar y tu boca para hablar.

tus oídos y ojos son corrientes

Esperemos que en estos ejemplos note que las metáforas de la corriente solo existen para permitir que algo viaje a través de ella (o en ella en el caso de la autopista) y no siempre plantean lo que están transfiriendo. Una distinción importante. No nos referimos a nuestros oídos como una secuencia de palabras. Una manguera sigue siendo una manguera si no fluye agua a través de ella, pero tenemos que conectarla a una espita para que haga su trabajo correctamente. Un automóvil no es el único 'tipo' de vehículo que puede atravesar una autopista.

Por lo tanto, puede existir una secuencia que no tenga datos viajando a través de ella siempre que esté conectada a un archivo .

Eliminar la abstracción

A continuación, debemos responder algunas preguntas. Voy a usar archivos para describir transmisiones, así que ... ¿Qué es un archivo? ¿Y cómo leemos un archivo? Intentaré responder esto manteniendo un cierto nivel de abstracción para evitar una complejidad innecesaria y utilizaré el concepto de un archivo relativo a un sistema operativo Linux debido a su simplicidad y accesibilidad.

¿Qué es un archivo?

Un archivo es una abstracción :)

O, tan simple como puedo explicar, un archivo es una estructura de datos de una parte que describe el archivo y los datos de una parte que es el contenido real.

La parte de la estructura de datos (llamada inodo en sistemas UNIX / linux) identifica piezas importantes de información sobre el contenido, pero no incluye el contenido en sí (o un nombre del archivo). Una de las piezas de información que guarda es una dirección de memoria donde comienza el contenido. Entonces, con un nombre de archivo (o un enlace duro en Linux), un descriptor de archivo (un nombre de archivo numérico que le importa al sistema operativo) y una ubicación inicial en la memoria, tenemos algo que podemos llamar un archivo.

(la clave para llevar es un 'archivo' definido por el sistema operativo ya que es el sistema operativo el que finalmente tiene que lidiar con él. Y sí, los archivos son mucho más complejos).

Hasta aquí todo bien. Pero, ¿cómo podemos obtener el contenido del archivo, decir una carta de amor a su novio, para que podamos imprimirlo?

Leyendo un archivo

Si comenzamos desde el resultado y retrocedemos, cuando abrimos un archivo en nuestra computadora, todo su contenido se salpica en nuestra pantalla para que lo podamos leer. ¿Pero cómo? Muy metódicamente es la respuesta. El contenido del archivo en sí es otra estructura de datos. Supongamos una serie de caracteres. También podemos pensar en esto como una cadena.

Entonces, ¿cómo 'leemos' esta cadena? Al encontrar su ubicación en la memoria e iterar a través de nuestra matriz de caracteres, un carácter a la vez hasta llegar al final del carácter de archivo. En otras palabras, un programa.

Una secuencia se 'crea' cuando se llama a su programa y tiene una ubicación de memoria para conectarse o conectarse . Al igual que nuestro ejemplo de manguera de agua, la manguera es ineficaz si no está conectada a una espita. En el caso de la transmisión, debe estar conectada a un archivo para que exista.

Las secuencias se pueden refinar aún más, por ejemplo, una secuencia para recibir entrada o una secuencia para enviar el contenido de un archivo a la salida estándar. UNIX / linux conecta y mantiene abiertos 3 flujos de archivos para nosotros de inmediato, stdin (entrada estándar), stdout (salida estándar) y stderr (error estándar). Las secuencias se pueden construir como estructuras de datos en sí mismas u objetos, lo que nos permite realizar operaciones más complejas de la transmisión de datos a través de ellas, como abrir la secuencia, cerrar la secuencia o verificar el archivo al que está conectada una secuencia. C ++ cines un ejemplo de un objeto de flujo.

Seguramente, si así lo elige, puede escribir su propia transmisión.

Definición

Un flujo es una pieza de código reutilizable que abstrae la complejidad de tratar con datos mientras proporciona operaciones útiles para realizar en datos.

rekurzion
fuente
Entonces, una secuencia es el medio a través del cual fluyen los datos. Tiene que estar conectado a la fuente de datos, y puede realizar operaciones sobre sí mismo y los datos que fluyen a través de él.
KingBryan
si. mi única razón para escribir una respuesta adicional fue aclarar que una secuencia puede existir incluso si los datos no fluyen a través de ella. mientras que una corriente IRL (con agua y tal) deja de ser una corriente cuando el agua deja de fluir y puede causar confusión al pensar en la analogía.
rekurzion
1
Actualmente estoy aprendiendo Java, y su respuesta me ayudó a entenderlo.
KingBryan
6

Además de las cosas mencionadas anteriormente, hay un tipo diferente de flujos, como se define en lenguajes de programación funcionales como Scheme o Haskell, una estructura de datos posiblemente infinita que es generada por alguna función a pedido.

EFraim
fuente
6

Otra analogía: no puede nadar contra una secuencia, es por eso que solo puede tomar el siguiente bit, byte, cadena u objeto de la secuencia, mientras se eliminan los datos ya leídos. Un boleto de ida ... o básicamente solo una cola sin almacenar persistencia.

Entonces, ¿necesitamos colas? Tú decides.

Marcus
fuente
significa que en una secuencia, tienes que avanzar no puedes retroceder. Además, los datos anteriores se eliminan a medida que avanza, lo que guarda la memoria, ¿verdad?
Muhammad Faizan Khan
5

La palabra "transmisión" ha sido elegida porque representa (en la vida real) un significado muy similar a lo que queremos transmitir cuando la usamos.

Comienza a pensar en la analogía de una corriente de agua. Recibe un flujo continuo de datos, al igual que el agua fluye continuamente en un río. No necesariamente sabe de dónde provienen los datos, y la mayoría de las veces no es necesario; ya sea desde un archivo, un socket o cualquier otra fuente, realmente no debería (no debería) importar. Esto es muy similar a recibir una corriente de agua, por lo que no necesita saber de dónde viene; ya sea de un lago, una fuente o cualquier otra fuente, realmente no debería importar. fuente

Premraj
fuente