Read: примеры (JAVA)

Справочник по чтению данных в Java
Раздел: Ввод-вывод (I/O) файловый
read: int

Общие сведения о методах read в Java

В Java нет единой глобальной функции read. Под этим именем чаще всего понимаются методы чтения из потоков и читателей: InputStream.read(), InputStream.read(byte[]), Reader.read(char[]), BufferedReader.readLine(), а также утилитные методы из Files и NIO: Files.readAllBytes, Files.readString, InputStream.readNBytes и т. д. Эти методы используются для получения данных из файлов, сетевых соединений, ресурсов и других источников данных.

Когда применять

  • Низкоуровневое побайтовое чтение - InputStream и его реализации.
  • Символьное чтение с учетом кодировки - Reader и подтипы.
  • Чтение строк - BufferedReader.readLine() или Scanner.
  • Простое чтение всего файла в память - Files.readAllBytes или Files.readString (для небольших файлов).

Основные сигнатуры и поведение

  • int InputStream.read()

    Возвращает следующий байт (0..255) в виде int. Возвращает -1, если достигнут EOF. Может блокироваться, если данных нет.

  • int InputStream.read(byte[] b)

    Читает до b.length байт в массив. Возвращает число реально прочитанных байт или -1 при EOF. Не гарантирует заполнение массива полностью.

  • int InputStream.read(byte[] b, int off, int len)

    Пишет в массив с указанного смещения до len байт. Возвращаемое значение аналогично.

  • int Reader.read(char[] cbuf)

    Аналогично для символов. Возвращает число прочитанных символов или -1 при EOF. Кодировка учитывается заранее через конкретную реализацию (например, InputStreamReader).

  • String BufferedReader.readLine()

    Возвращает строку без символа новой строки или null при EOF. Используется для построчного чтения текста.

  • byte[] Files.readAllBytes(Path path)

    Читает весь файл целиком в массив байт. Генерирует исключение при ошибке ввода-вывода. Подходит только для файлов умеренного размера.

  • String Files.readString(Path path)

    Начиная с Java 11 читает весь файл как строку с указанной кодировкой по умолчанию UTF-8 для перегрузки без кодировки. Может выбросить IOException.

  • byte[] InputStream.readNBytes(int len)

    Возвращает ровно до len байт или меньше, если EOF. Введено в более поздних версиях как удобство для безопасного чтения фиксированного объема.

Возвращаемые значения и исключения

  • Числовые методы возвращают количество прочитанных байт/символов или -1 при EOF.
  • Методы, возвращающие массивы или строки, возвращают данные или выбрасывают IOException при ошибке.
  • Для сетевых и неблокирующих каналов поведение может отличаться: чтение может вернуть 0 или блокироваться в зависимости от режима.

Примечания по потокам и кодировке

  • Для текстовых данных предпочтительнее использовать Reader или Files.readString с указанием кодировки.
  • Для бинарных данных использовать InputStream, FileChannel или memory-mapped файлы.
  • Необходимо учитывать возможное неполное заполнение буфера и обрабатывать возвращаемое число прочитанных байт.

Короткие примеры использования методов read

1. InputStream.read() одиночный байт

import java.io.FileInputStream;
import java.io.IOException;

public class Example1 {
    public static void main(String[] args) throws IOException {
        try (FileInputStream in = new FileInputStream("test.bin")) {
            int b = in.read();
            System.out.println(b); // int от 0 до 255 или -1
        }
    }
}
Если первый байт файла 0x41 вывод будет:
65

2. InputStream.read(byte[])

import java.io.FileInputStream;
import java.io.IOException;

public class Example2 {
    public static void main(String[] args) throws IOException {
        try (FileInputStream in = new FileInputStream("hello.txt")) {
            byte[] buf = new byte[8];
            int n = in.read(buf);
            System.out.println(n);
            System.out.println(new String(buf, 0, Math.max(0, n))); // печать прочитанного
        }
    }
}
Если файл содержит "Hello, world" вывод может быть:
8
Hello, w

3. BufferedReader.readLine()

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class Example3 {
    public static void main(String[] args) throws IOException {
        try (BufferedReader br = new BufferedReader(new FileReader("lines.txt"))) {
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
        }
    }
}
Для файла с двумя строками вывод будет:
Первая строка
Вторая строка

4. Files.readAllBytes и Files.readString

import java.nio.file.Files;
import java.nio.file.Path;
import java.io.IOException;

public class Example4 {
    public static void main(String[] args) throws IOException {
        byte[] all = Files.readAllBytes(Path.of("hello.txt"));
        System.out.println(all.length);
        String s = Files.readString(Path.of("hello.txt")); // Java 11+
        System.out.println(s);
    }
}
Если файл содержит "Hello":
5
Hello

5. InputStream.readNBytes (Java 9+)

import java.io.FileInputStream;
import java.io.IOException;

public class Example5 {
    public static void main(String[] args) throws IOException {
        try (FileInputStream in = new FileInputStream("hello.txt")) {
            byte[] part = in.readNBytes(3); // старается вернуть ровно 3 байта, если есть
            System.out.println(part.length);
            System.out.println(new String(part));
        }
    }
}
Для файла "Hello" вывод:
3
Hel

Похожие методы в Java и их особенности

  • InputStream vs Reader
  • InputStream работает с байтами. Reader предназначен для символов и учитывает кодировку. Для текстовых файлов предпочтительнее Reader или оборачивание InputStream в InputStreamReader.

  • Files.readAllBytes / Files.readString vs BufferedReader
  • Files.readAllBytes/readString читают весь файл в память. BufferedReader позволяет читать построчно и экономить память при больших файлах.

  • Scanner
  • Scanner удобен для парсинга токенов и простого чтения по шаблонам, но медленнее и менее гибок для бинарных данных или точного управления чтением.

  • FileChannel и ByteBuffer
  • Для высокопроизводительного чтения больших файлов предпочтительнее NIO: FileChannel.read(ByteBuffer) и memory-mapped файлы через FileChannel.map.

  • AsynchronousFileChannel
  • Для неблокирующего асинхронного ввода-вывода в серверных приложениях может быть проще использовать AsynchronousFileChannel.

Выбор зависит от требований: кодировка и удобство работы с текстом, требования по памяти, производительность и блокирующее/неблокирующее поведение.

Аналоги в других языках и отличия от Java

  • PHP
  • file_get_contents считывает весь файл в строку, fopen/fread для потокового чтения. В отличие от Java, PHP не строг типами, но те же риски OOM при чтении больших файлов.

    // PHP
    $content = file_get_contents('hello.txt');
    echo $content;
    Hello
  • JavaScript (Node.js)
  • fs.readFileSync возвращает Buffer или строку, fs.createReadStream предоставляет поток. Node.js по умолчанию асинхронен и не блокирует весь поток исполнения.

    // Node.js
    const fs = require('fs');
    console.log(fs.readFileSync('hello.txt', 'utf8'));
    Hello
  • Python
  • open(...).read() читает всё; read(size) читает до size байт; итерация по файлу читает строки. Python проще в синтаксисе, но те же концепции: побайтовое чтение vs текстовое с декодированием.

    # Python
    with open('hello.txt', 'r', encoding='utf-8') as f:
        print(f.read())
    Hello
  • SQL
  • В SQL чтение файлов выполняется через функции СУБД (LOAD_FILE, COPY) и сильно зависит от привилегий и возможностей СУБД. Это не эквивалент методов read на уровне языка.

  • C#
  • File.ReadAllText / File.ReadAllBytes / Stream.Read и StreamReader похожи по семантике на Java. Имеются async/await версии для асинхронного ввода-вывода.

    // C#
    using System.IO;
    Console.WriteLine(File.ReadAllText("hello.txt"));
    Hello
  • Lua
  • io.open и :read позволяют читать строки или блоки. Меньше стандартной инфраструктуры по сравнению с Java, но простая работа с файлами возможна.

    -- Lua
    local f = io.open('hello.txt', 'r')
    print(f:read('*a'))
    f:close()
    Hello
  • Go (Golang)
  • io.Reader интерфейс и функции ioutil.ReadFile (ReadFile -> os.ReadFile в новых версиях). Подход похож на Java NIO, но с выделением интерфейса Reader/Writer и удобными утилитами.

    // Go
    package main
    import (
      "fmt"
      "os"
    )
    func main() {
      b, _ := os.ReadFile("hello.txt")
      fmt.Println(string(b))
    }
    Hello
  • Kotlin
  • Kotlin работает поверх JVM и использует те же методы Files, InputStream, но предлагает расширения и удобные API, например File.readText() и File.readBytes().

    // Kotlin
    import java.io.File
    println(File("hello.txt").readText())
    Hello

Отличия в основном в синтаксисе и парадигме (синхронный vs асинхронный по умолчанию), а также в наличии удобных стандартных функций для чтения всего файла.

Типичные ошибки и примеры

1. Игнорирование возвращаемого значения read(byte[])

import java.io.FileInputStream;
import java.io.IOException;

public class Bug1 {
    public static void main(String[] args) throws IOException {
        try (FileInputStream in = new FileInputStream("small.txt")) {
            byte[] buf = new byte[1024];
            in.read(buf); // неверно: не проверяется число прочитанных байт
            System.out.println(new String(buf));
        }
    }
}
Если в файле 5 байт, вывод может содержать мусор или нулевые символы после первых 5 байт.

2. Чтение всего большого файла в память

import java.nio.file.Files;
import java.nio.file.Path;
import java.io.IOException;

public class Bug2 {
    public static void main(String[] args) throws IOException {
        byte[] all = Files.readAllBytes(Path.of("huge.bin")); // риск OOM
        System.out.println(all.length);
    }
}
При больших файлах возможен OutOfMemoryError

3. Неправильная обработка кодировки

import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;

public class Bug3 {
    public static void main(String[] args) throws Exception {
        try (BufferedReader br = new BufferedReader(new InputStreamReader(
                new FileInputStream("utf8.txt")))) { // по умолчанию может использоваться платформа-зависимая кодировка
            System.out.println(br.readLine());
        }
    }
}
Если файл в UTF-8, а платформа использует другую кодировку, возможен искаженный вывод. Предпочтительнее указывать Charset явно.

4. Не закрытые ресурсы

import java.io.FileInputStream;

public class Bug4 {
    public static void main(String[] args) throws Exception {
        FileInputStream in = new FileInputStream("file.txt");
        int b = in.read();
        // in.close() забыто, ресурс остается открытым
    }
}
В большинстве случаев ресурс будет закрыт при завершении приложения, но в серверных приложениях это приводит к утечкам дескрипторов и ошибкам.

5. Неправильное ожидание полного заполнения буфера

// Неправильно предполагать, что один вызов read заполнит весь buf
byte[] buf = new byte[4096];
int n = in.read(buf);
if (n != buf.length) {
    // многие считают, что так быть не должно, но на практике read может вернуть меньше
}
read может вернуть любое число от 1 до buf.length или -1. Для гарантированного чтения N байт нужно циклить или использовать readNBytes.

Изменения и новинки в последних версиях Java

  • Java 9: добавлены InputStream.readAllBytes() и InputStream.readNBytes(int), что упрощает чтение фиксированного количества байт.
  • Java 9+: улучшения в NIO и FileChannel, работа с direct buffers и улучшения производительности.
  • Java 11: Files.readString(Path) и Files.writeString для удобного чтения и записи текста. Это упрощает чтение всего файла как строки с использованием UTF-8 по умолчанию в соответствующих перегрузках.
  • try-with-resources (Java 7): рекомендованная практика закрытия ресурсов автоматически через AutoCloseable.

Эти изменения добавляют удобные утилиты и помогают избежать распространенных ошибок, но основная семантика классов InputStream, Reader и NIO осталась прежней.

Расширенные и редкие сценарии использования

1. Memory-mapped файл для быстрого доступа (FileChannel.map)

Пример java
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

public class Adv1 {
    public static void main(String[] args) throws Exception {
        try (RandomAccessFile raf = new RandomAccessFile("big.dat", "r");
             FileChannel ch = raf.getChannel()) {
            MappedByteBuffer mb = ch.map(FileChannel.MapMode.READ_ONLY, 0, ch.size());
            byte b = mb.get(0);
            System.out.println(b);
        }
    }
}
Вывод: первый байт файла в виде целого числа от -128 до 127

2. Чтение бинарных структур через ByteBuffer и DataInputStream

Пример java
import java.io.DataInputStream;
import java.io.FileInputStream;

public class Adv2 {
    public static void main(String[] args) throws Exception {
        try (DataInputStream dis = new DataInputStream(new FileInputStream("record.bin"))) {
            int id = dis.readInt();
            short flags = dis.readShort();
            System.out.println("id=" + id + " flags=" + flags);
        }
    }
}
Вывод будет зависеть от содержимого record.bin, например:
id=12345 flags=7

3. Асинхронное чтение файла (AsynchronousFileChannel)

Пример java
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.file.Path;
import java.util.concurrent.Future;

public class Adv3 {
    public static void main(String[] args) throws Exception {
        try (AsynchronousFileChannel ch = AsynchronousFileChannel.open(Path.of("hello.txt"))) {
            ByteBuffer buf = ByteBuffer.allocate(64);
            Future fut = ch.read(buf, 0);
            int n = fut.get();
            buf.flip();
            byte[] arr = new byte[n];
            buf.get(arr);
            System.out.println(new String(arr));
        }
    }
}
Hello

4. Построчная обработка больших файлов с ограничением памяти

Пример java
import java.io.BufferedReader;
import java.io.FileReader;

public class Adv4 {
    public static void main(String[] args) throws Exception {
        try (BufferedReader br = new BufferedReader(new FileReader("big.txt"))) {
            String line;
            long lines = 0;
            while ((line = br.readLine()) != null) {
                // обработка строки без хранения всего файла
                lines++;
            }
            System.out.println("lines=" + lines);
        }
    }
}
lines=1234567

5. Чтение с точным числом байт в цикле

Пример java
import java.io.FileInputStream;
import java.io.IOException;

public class Adv5 {
    public static void main(String[] args) throws IOException {
        try (FileInputStream in = new FileInputStream("data.bin")) {
            int toRead = 10000;
            byte[] buffer = new byte[toRead];
            int offset = 0;
            while (offset < toRead) {
                int n = in.read(buffer, offset, toRead - offset);
                if (n == -1) break; // EOF
                offset += n;
            }
            System.out.println("read=" + offset);
        }
    }
}
read=10000 или меньше если EOF раньше

6. Декодирование части байтов корректно: CharsetDecoder

Пример java
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;

public class Adv6 {
    public static void main(String[] args) throws Exception {
        CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();
        try (FileInputStream in = new FileInputStream("utf8.txt")) {
            byte[] b = new byte[5];
            int n = in.read(b);
            ByteBuffer bb = ByteBuffer.wrap(b, 0, Math.max(0, n));
            CharBuffer cb = decoder.decode(bb);
            System.out.println(cb.toString());
        }
    }
}
Вывод: корректно декодированная часть текста без искажения символов

7. Чтение из сокета (InputStream от Socket)

Пример java
import java.net.Socket;
import java.io.InputStream;

public class Adv7 {
    public static void main(String[] args) throws Exception {
        try (Socket s = new Socket("example.com", 80);
             InputStream in = s.getInputStream()) {
            // отправить HTTP запрос отдельно
            byte[] buf = new byte[1024];
            int n = in.read(buf);
            System.out.println(new String(buf, 0, n));
        }
    }
}
Вывод: первые байты ответа сервера, например HTTP заголовки

Эти примеры показывают, как применять разные механизмы чтения в реальных и редких сценариях, оптимизируя память, производительность и корректность декодирования.

джава read function comments

En
Read Reads a byte of data from this input stream