Потоки байт

InputStream и OutputStream — абстракции последовательного ввода/вывода байтов. Источник может быть файлом, сокетом, массивом, архивом.

Контракт чтения

int value = input.read();

Метод возвращает 0..255 либо -1 при EOF. Поэтому нельзя сначала приводить результат к byte, а затем проверять -1: значение байта 0xff тоже станет -1.

Блочное копирование:

static long copy(InputStream input, OutputStream output)
        throws IOException {
    byte[] buffer = new byte[8192];
    long total = 0;
    int read;
 
    while ((read = input.read(buffer)) != -1) {
        output.write(buffer, 0, read);
        total += read;
    }
    return total;
}

Один read(buffer) не обязан заполнить buffer. Использовать нужно только первые read байтов.

В современных JDK есть input.transferTo(output), но владение потоками и закрытие все равно определяет вызывающий код.

Ресурсы и буферы

try (InputStream input = Files.newInputStream(source);
     OutputStream output = new BufferedOutputStream(
             Files.newOutputStream(target))) {
    input.transferTo(output);
}

flush() проталкивает данные из Java-буферов к следующему слою, но не обещает физическую запись на носитель. close() обычно вызывает flush и освобождает ресурс. Не закрывать поток, которым владеет вызывающий код, без явного контракта.

Обертки

  • BufferedInputStream/OutputStream уменьшают число обращений к нижнему слою;
  • ByteArrayInputStream/OutputStream работают в памяти;
  • DataInputStream/OutputStream читают/пишут примитивы в согласованном бинарном формате;
  • GZIPInputStream/OutputStream добавляют сжатие;
  • InputStreamReader декодирует байты в символы — Потоки символов.

Для Data* порядок и тип чтения должны совпадать с записью. Такой ad-hoc формат нужно версионировать, если он хранится долго.

На собеседовании

  • Почему read() возвращает int? Чтобы представить все 256 байтов и отдельный EOF -1.
  • Гарантирует ли read(buffer) полный буфер? Нет.
  • Что пишет write(int)? Младшие 8 бит.
  • Что гарантирует flush? Передачу буферизованных данных нижнему слою, не fsync диска.
  • Кто должен закрывать stream? Его владелец по контракту.