Low-level streams read directly from the input medium or write directly to the output medium. Eg. a FileInputStream reads raw bytes from a file. High-level streams are streams that read from or write to other streams. Eg. a BufferedInputStream may be used to read chunks of bytes from a FileInputStream. The constructor of high-level streams always takes an other stream as an argument; the constructors of low-level streams do never accept streams as arguments. However, both kinds of streams, low-level as well as high-level streams extend the same abstract superclasses. In order to use streams, you need to know what the purposes of the individual streams. There is no easy way - you have to learn them. Please let me know if I'm wrong.