Notice that files and streams are quite different things. Files are just sequences of bytes, while Streams are just facilitators(helpers).
Streams come in the picture since all programs need to interact with their surrounding environment in many different forms(could be files, could be I/O devices such as monitor and keyboard, could be network sockets and etc.).
So a stream is an interface(an easy "face" to work with something that has many subtleties irrelevant to us, just like we don't need to know how a TV remote works!) for triggering input/output flow of data, from/to anything that can be a source/destination to that input/output data, hiding the low-level implementation details of the numerous methodologies that OSs devise in order to interact with the variously designed hardware, on behalf of the programmers(i.e., We -as programmers- are not really interested in re-programming the way an operating system interacts with various hardware every time we create new software).
So for instance, thinking about the way our program can get input from the keyboard..., how does that happen? That happens through a hidden(hidden to the programmer) stream that the OS provides for every "process"(As soon as a program is run, it will be what's called a process), and the OS gives the address to the standard stream made for a process to it automatically(i.e., we won't need to write code to locate its address). This stream is commonly called the "stdin"(rooted in the C & Unix terminology), or more formally called "The Standard Input Stream". Our programs, no matter written in what language, must be able to use such standard streams made by the OS through the standard I/O libraries of that language. As an example, in the C programming language, we may scan the standard input stream by calling the function "scanf"(scanf will know where the stdin of our program is automatically).
But as another important example, again in C, let's say this time our program wants to write user's input to a "file"... Does only the existence of the stdin stream suffice in this situation? Of course not! This time, we'll need to use a pair of streams, one already provided by the OS, the stdin, to get the user's input, and a second one, to let the communication between our program and the file! So we will have to create this second stream! Something which can be done by calling the fopen()
function. (Fun Fact: In the manual, if you notice, you will see that the returned type of this function is a pointer to a structure called FILE, but that’s only a traditional “bad choice of word” for what's actually a pointer to a "stream"! Yes, the type FILE in C is indeed a stream, and not a file!(I see, crazy!) So remember, the pointer FILE* does NOT point to the actual file, it points to a stream containing the information about that file, including information about the buffer used for the file's I/O and etc.)
Notice: The streams we create ourselves(for instance file streams) can be bidirectional, while standard streams are unidirectional. This is also illustrated nicely with arrows in the picture below:
Also as an example in the C++ world to give you a comparison, you know that in there, things are in classes instead of structures, so you will encounter an object called "cout"(the output stream object) if you're outputting, which is an object connected to the output stream(stdout in C), and is an instance of the class ostream(from the class hierarchy ios_base <-- ios <-- ostream). To write to the standard output stream using cout, its "<<" method(corresponding to printf() in C) must be used. This time again, cout will not suffice for interacting with other things(such as files) and we'll need to create our own streams. In C++, it can be done by instantiating the ifstream and ofstream classes(corresponding to FILE structure in C) which will result in objects that basically play the same role as the pointer "FILE*" in C.
Hope That Helps.
illustration's credit to linuxhint.com