Che cos'è uno stream?


Risposte:


161

Un flusso rappresenta una sequenza di oggetti (in genere byte, ma non necessariamente), a cui è possibile accedere in ordine sequenziale. Operazioni tipiche su uno stream:

  • leggere un byte. La prossima volta che leggi, otterrai il byte successivo e così via.
  • leggere diversi byte dallo stream in un array
  • cerca (sposta la tua posizione corrente nello stream, in modo che la prossima volta che leggi ottieni byte dalla nuova posizione)
  • scrivi un byte
  • scrivere diversi byte da un array nel flusso
  • salta byte dallo stream (è come leggere, ma ignori i dati. O se preferisci è come cercare ma puoi solo andare avanti.)
  • spingere indietro i byte in un flusso di input (questo è come "annulla" per leggere - si sposta di alcuni byte indietro nel flusso, in modo che la prossima volta che leggerai è quello che vedrai. Occasionalmente è utile per i parser, come è:
  • sbirciata (guarda i byte senza leggerli, in modo che siano ancora lì nello stream per essere letti in seguito)

Un flusso particolare potrebbe supportare la lettura (nel qual caso si tratta di un "flusso di input"), la scrittura ("flusso di output") o entrambi. Non tutti i flussi sono ricercabili.

Il push back è abbastanza raro, ma è sempre possibile aggiungerlo a uno stream avvolgendo il flusso di input reale in un altro flusso di input che contiene un buffer interno. Le letture provengono dal buffer e, se si esegue il push back, i dati vengono inseriti nel buffer. Se non c'è nulla nel buffer, il flusso push back legge dal flusso reale. Questo è un semplice esempio di "adattatore di flusso": si trova all'estremità di un flusso di input, è un flusso di input stesso e fa qualcosa in più rispetto al flusso originale.

Lo stream è un'astrazione utile perché può descrivere file (che sono realmente array, quindi la ricerca è semplice) ma anche input / output del terminale (che non è ricercabile a meno che non sia bufferizzato), socket, porte seriali, ecc. Quindi puoi scrivere codice che dice o "Voglio alcuni dati e non mi interessa da dove vengono o come sono arrivati ​​qui", o "Produrrò alcuni dati, e dipende interamente dal mio chiamante cosa succede". Il primo accetta un parametro del flusso di input, il secondo accetta un parametro del flusso di output.

La migliore analogia a cui riesco a pensare è che un flusso è un nastro trasportatore che viene verso di te o ti allontana (o talvolta entrambi). Prendi le cose da un flusso di input, metti cose in un flusso di output. Alcuni nastri trasportatori che puoi immaginare escano da un buco nel muro: non sono ricercabili, leggere o scrivere è un affare solo una volta. Alcuni nastri trasportatori sono disposti di fronte a te e puoi spostarti scegliendo la posizione nello stream che vuoi leggere / scrivere - che sta cercando.

Come dice IRBMe, tuttavia, è meglio pensare a un flusso in termini di operazioni che offre (che variano da implementazione a implementazione, ma hanno molto in comune) piuttosto che per analogia fisica. Gli stream sono "cose ​​che puoi leggere o scrivere". Quando si avvia la connessione degli adattatori di flusso, è possibile considerarli come una scatola con un convogliatore in entrata e un convogliatore in uscita, che si connette ad altri flussi e quindi la scatola esegue una trasformazione dei dati (zippandola o modificando gli avanzamenti di riga UNIX a quelli DOS o altro). Le pipe sono un altro test approfondito della metafora: è lì che crei una coppia di flussi in modo tale che qualsiasi cosa tu scriva in una possa essere letta dall'altra. Pensa ai wormhole :-)


3
Di gran lunga la migliore spiegazione che ho letto. Insieme a ciò che dice in SICP ("L'elaborazione del flusso ci consente di modellare i sistemi che hanno uno stato senza mai usare assegnazioni o dati mutabili"), penso di averlo finalmente capito. Grazie!
Kyle Chadha,

85

Uno stream è già una metafora, un'analogia, quindi non c'è davvero bisogno di anticiparne un altro. Puoi pensarlo fondamentalmente come un tubo con un flusso di acqua in cui l'acqua è in realtà dati e il tubo è il flusso. Suppongo che sia una specie di tubo a 2 vie se il flusso è bidirezionale. È fondamentalmente un'astrazione comune che viene posta su cose in cui vi è un flusso o una sequenza di dati in una o entrambe le direzioni.

In linguaggi come C #, VB.Net, C ++, Java ecc., La metafora dello stream viene utilizzata per molte cose. Esistono flussi di file, in cui si apre un file e si può leggere dallo stream o scriverlo continuamente; Esistono flussi di rete in cui la lettura e la scrittura nel flusso legge e scrive su una connessione di rete stabilita sottostante. I flussi per la sola scrittura sono in genere chiamati flussi di output, come in questo esempio, e allo stesso modo, i flussi che sono di sola lettura sono chiamati flussi di input, come in questo esempio.

Un flusso può eseguire la trasformazione o la codifica dei dati (uno SslStream in .Net, ad esempio, divorerà i dati di negoziazione SSL e li nasconderà da te; un TelnetStream potrebbe nascondere le negoziazioni di Telnet da te, ma fornire l'accesso ai dati; A ZipOutputStream in Java consente di scrivere su file in un archivio zip senza doversi preoccupare degli interni del formato di file zip.

Un'altra cosa comune che potresti trovare sono flussi testuali che ti permettono di scrivere stringhe invece di byte, o alcune lingue forniscono flussi binari che ti permettono di scrivere tipi primitivi. Una cosa comune che troverai nei flussi testuali è una codifica dei caratteri, di cui dovresti essere consapevole.

Alcuni stream supportano anche l'accesso casuale, come in questo esempio. Un flusso di rete, d'altra parte, per ovvie ragioni, non lo farebbe.

  • MSDN offre una buona panoramica dei flussi in .Net.
  • Sun offre anche una panoramica della classe generale OutputStream e della classe InputStream .
  • In C ++, ecco la documentazione di istream (flusso di input), ostream (flusso di output) e iostream (flusso bidirezionale).

Anche i sistemi operativi UNIX supportano il modello di flusso con input e output del programma, come descritto qui .


13

Le risposte fornite finora sono eccellenti. Ne sto fornendo un altro per evidenziare che uno stream non è una sequenza di byte o specifico di un linguaggio di programmazione poiché il concetto è universale (mentre la sua implementazione può essere unica). Vedo spesso molte spiegazioni online in termini di SQL, o C o Java, che hanno senso come un filestream si occupa di posizioni di memoria e operazioni di basso livello. Ma spesso affrontano come creare un filestream e operare sul file potenziale nella loro lingua, piuttosto che discutere il concetto di stream.

La metafora

Come detto a streamè una metafora, un'astrazione di qualcosa di più complesso. Per far funzionare la tua immaginazione offro alcune altre metafore:

  1. vuoi riempire una piscina vuota con acqua. un modo per raggiungere questo obiettivo è quello di collegare un tubo a un rubinetto, posizionando l'estremità del tubo nella piscina e aprendo l'acqua.

il tubo è il flusso

  1. allo stesso modo, se si desidera riempire la propria auto di gas, si dovrebbe andare a una pompa di benzina, inserire l'ugello nel serbatoio del gas e aprire la valvola premendo la leva di bloccaggio.

il tubo flessibile, l'ugello e i meccanismi associati per consentire al gas di fluire nel serbatoio è il flusso

  1. se hai bisogno di andare al lavoro, inizieresti a guidare da casa in ufficio usando l'autostrada senza pedaggio.

l'autostrada senza pedaggio è il flusso

  1. se vuoi avere una conversazione con qualcuno, useresti le orecchie per ascoltare e la bocca per parlare.

le tue orecchie e i tuoi occhi sono flussi

Si spera che in questi esempi si noti che le metafore del flusso esistono solo per consentire a qualcosa di attraversarlo (o su di esso nel caso dell'autostrada senza pedaggio) e non si pongono sempre ciò che stanno trasferendo. Una distinzione importante. Non ci riferiamo alle nostre orecchie come una sequenza di parole. Un tubo è ancora un tubo se non vi scorre acqua, ma dobbiamo collegarlo a un rubinetto perché faccia correttamente il suo lavoro. Un'auto non è l'unico "tipo" di veicolo che può attraversare un'autostrada senza pedaggio.

Pertanto può esistere uno stream che non ha dati che lo attraversano finché è collegato a un file .

Rimozione dell'astrazione

Successivamente, dobbiamo rispondere ad alcune domande. Userò i file per descrivere i flussi, quindi ... Cos'è un file? E come leggiamo un file? Cercherò di rispondere a questo mantenendo un certo livello di astrazione per evitare complessità non necessarie e userò il concetto di un file relativo a un sistema operativo Linux per la sua semplicità e accessibilità.

Che cos'è un file?

Un file è un'astrazione :)

Oppure, per quanto posso spiegare, un file è una struttura di dati di una parte che descrive il file e una parte di dati che è il contenuto effettivo.

La parte della struttura dei dati (chiamata inode nei sistemi UNIX / linux) identifica importanti informazioni sul contenuto, ma non include il contenuto stesso (o un nome del file per quella materia). Una delle informazioni che conserva è un indirizzo di memoria a cui inizia il contenuto. Quindi con un nome di file (o un hard link in linux), un descrittore di file (un nome di file numerico a cui tiene il sistema operativo) e una posizione iniziale in memoria abbiamo qualcosa che possiamo chiamare un file.

(la chiave da asporto è un 'file' definito dal sistema operativo in quanto è il sistema operativo che alla fine deve occuparsene. E sì, i file sono molto più complessi).

Fin qui tutto bene. Ma come possiamo ottenere il contenuto del file, dire una lettera d'amore al tuo fidanzato, così possiamo stamparlo?

Lettura di un file

Se partiamo dal risultato e ci spostiamo all'indietro, quando apriamo un file sul nostro computer, l'intero contenuto viene schizzato sullo schermo per consentirci di leggere. Ma come? Molto metodicamente è la risposta. Il contenuto del file stesso è un'altra struttura di dati. Supponiamo una matrice di personaggi. Possiamo anche pensare a questo come a una stringa.

Quindi, come possiamo "leggere" questa stringa? Trovando la sua posizione nella memoria e ripetendo la nostra gamma di caratteri, un carattere alla volta fino a raggiungere la fine del carattere del file. In altre parole, un programma.

Uno stream viene "creato" quando viene chiamato il suo programma e ha una posizione di memoria a cui collegarsi o connettersi . Proprio come il nostro esempio di tubo dell'acqua, il tubo è inefficace se non è collegato a un rubinetto. Nel caso del flusso, deve essere collegato a un file per esistere.

Gli stream possono essere ulteriormente perfezionati, ad esempio uno stream per ricevere input o uno stream per inviare i contenuti di un file all'output standard. UNIX / linux si connette e mantiene aperti 3 filestream per noi subito, bat, stdin (input standard), stdout (output standard) e stderr (errore standard). I flussi possono essere creati come strutture di dati stesse o oggetti che ci consentono di eseguire operazioni più complesse del flusso di dati attraverso di essi, come l'apertura del flusso, la chiusura del flusso o l'errore nel controllo del file a cui è collegato un flusso. C ++ cinè un esempio di un oggetto stream.

Sicuramente, se lo desideri, puoi scrivere il tuo stream.

Definizione

Un flusso è un pezzo di codice riutilizzabile che riassume la complessità della gestione dei dati e allo stesso tempo fornisce operazioni utili da eseguire sui dati.


Quindi uno stream è il mezzo attraverso cui fluiscono i dati. Deve essere collegato alla fonte dei dati e può eseguire operazioni su se stesso e sui dati che lo attraversano.
KingBryan

sì. la mia unica ragione per scrivere una risposta aggiuntiva era chiarire che un flusso può esistere anche se i dati non lo attraversano. mentre un flusso IRL (con acqua e simili) cessa di essere un flusso quando l'acqua smette di fluire e può causare confusione quando si pensa all'analogia.
rekurzion,

1
Attualmente sto imparando Java e la tua risposta mi ha aiutato a avvolgerci la testa.
KingBryan,

6

Oltre alle cose sopra menzionate, esiste un diverso tipo di flussi - come definito in linguaggi di programmazione funzionale come Scheme o Haskell - una struttura di dati forse infinita che viene generata da alcune funzioni su richiesta.


6

Un'altra analogia: non puoi nuotare contro uno stream, ecco perché puoi semplicemente prendere il bit, il byte, la stringa o l'oggetto successivi dallo stream, mentre i dati già letti vengono eliminati. Un biglietto di sola andata ... o sostanzialmente solo una coda senza memorizzare persistenza.

Quindi abbiamo bisogno di code? Tu decidi.


significa che in un flusso, devi andare avanti non puoi muoverti indietro. Inoltre, i dati precedenti sono stati eliminati man mano che si va avanti per salvare la memoria? Giusto
Muhammad Faizan Khan

5

La parola "flusso" è stata scelta perché rappresenta (nella vita reale) un significato molto simile a ciò che vogliamo trasmettere quando lo usiamo.

Inizia a pensare all'analogia con un flusso d'acqua. Ricevi un flusso continuo di dati, proprio come l'acqua scorre continuamente in un fiume. Non necessariamente sai da dove provengono i dati e molto spesso non è necessario; che si tratti di un file, di un socket o di qualsiasi altra fonte, non ha (non dovrebbe) importare davvero. Questo è molto simile alla ricezione di un flusso d'acqua, per cui non è necessario sapere da dove provenga; che si tratti di un lago, una fontana o qualsiasi altra fonte, non ha (non dovrebbe) importare davvero. fonte

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.