Потоки в java можно поделить на две части:
1.Потоки для соединений.
2.Цепные потоки.
Скачать исходники для статьи можно ниже
Потоки для соединений представляют собой подключение к источнику или пункту назначения (файлу, массиву, сокету и т.д.).
При передаче данных через потоки ввода-вывода обязательно должен быть один поток для соединения. Потоки для соединения обычно являются низкоуровневыми. Данные по ним передаются обычно в байтах. Иногда достаточно одного потока для соединения, однако в большинстве
случаев нам понадобится помощь цепных потоков.
Например, к потокам для соединения можно отнести:
FileOutputStream
FileInputStream
ByteArrayOutputStream
ByteArrayInputStream
Пример использования потока для соединения:
public class Main {
   public static void main(String[] args) throws IOException {
      File file1 = new File("file1.txt");
      // создается поток для соединения FileOutputStream
      FileOutputStream streamOut1 = new FileOutputStream(file1);
      // создается поток для соединения FileInputStream
      FileInputStream streamIn1 = new FileInputStream(file1);
      // запись в файл, поток FileOutputStream
      byte b = 99;
      streamOut1.write(b);
      b = 65;
      streamOut1.write(b);
      // чтение из файла, потока FileInputStream
      System.out.println(streamIn1.read());
      System.out.println(streamIn1.read());
      System.out.println(streamIn1.read());
      streamOut1.close();
      streamIn1.close();
   }
}
Вывод программы:
99
65
-1


