Le mot "stream" a été choisi parce qu'il représente (dans la vie réelle) une signification très similaire à celle que nous voulons transmettre lorsque nous l'utilisons.
Oublions un peu l'arrière-boutique et pensons à l'analogie avec un cours d'eau. Vous recevez un flux continu de données, tout comme l'eau coule continuellement dans une rivière. Vous ne savez pas nécessairement d'où viennent les données et, le plus souvent, vous n'en avez pas besoin ; qu'elles proviennent d'un fichier, d'un socket ou de toute autre source, cela n'a (devrait) pas vraiment d'importance. C'est très similaire à la réception d'un jet d'eau, pour lequel vous n'avez pas besoin de savoir d'où il provient ; que ce soit d'un lac, d'une fontaine ou de toute autre source, cela n'a pas (ne devrait pas) vraiment d'importance.
Cela dit, une fois que vous commencez à penser que vous ne vous souciez que d'obtenir les données dont vous avez besoin, quelle que soit leur provenance, les abstractions dont les autres personnes ont parlé deviennent plus claires. Vous commencez à penser que vous pouvez envelopper les flux, et que vos méthodes continueront à fonctionner parfaitement. Par exemple, vous pourriez faire ceci :
int ReadInt(StreamReader reader) { return Int32.Parse(reader.ReadLine()); }
// in another method:
Stream fileStream = new FileStream("My Data.dat");
Stream zipStream = new ZipDecompressorStream(fileStream);
Stream decryptedStream = new DecryptionStream(zipStream);
StreamReader reader = new StreamReader(decryptedStream);
int x = ReadInt(reader);
Comme vous le voyez, il devient très facile de changer votre source d'entrée sans modifier votre logique de traitement. Par exemple, pour lire vos données à partir d'un socket réseau au lieu d'un fichier :
Stream stream = new NetworkStream(mySocket);
StreamReader reader = new StreamReader(stream);
int x = ReadInt(reader);
Aussi simple que cela puisse être. Et la beauté continue, puisque vous pouvez utiliser n'importe quel type de source d'entrée, tant que vous pouvez construire un "wrapper" de flux pour elle. Vous pouvez même faire ça :
public class RandomNumbersStreamReader : StreamReader {
private Random random = new Random();
public String ReadLine() { return random.Next().ToString(); }
}
// and to call it:
int x = ReadInt(new RandomNumbersStreamReader());
Vous voyez ? Tant que votre méthode ne se soucie pas de la source d'entrée, vous pouvez personnaliser votre source de diverses manières. L'abstraction vous permet de découpler l'entrée de la logique de traitement d'une manière très élégante.
Notez que le flux que nous avons créé nous-mêmes ne dispose pas d'un backing store, mais il répond néanmoins parfaitement à nos besoins.
Donc, pour résumer, un flux est juste une source d'entrée, cachant (abstraction) une autre source. Tant que vous ne brisez pas l'abstraction, votre code sera très flexible.