Read: примеры (JAVA)
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
- Files.readAllBytes / Files.readString vs BufferedReader
- Scanner
- FileChannel и ByteBuffer
- AsynchronousFileChannel
InputStream работает с байтами. Reader предназначен для символов и учитывает кодировку. Для текстовых файлов предпочтительнее Reader или оборачивание InputStream в InputStreamReader.
Files.readAllBytes/readString читают весь файл в память. BufferedReader позволяет читать построчно и экономить память при больших файлах.
Scanner удобен для парсинга токенов и простого чтения по шаблонам, но медленнее и менее гибок для бинарных данных или точного управления чтением.
Для высокопроизводительного чтения больших файлов предпочтительнее NIO: FileChannel.read(ByteBuffer) и memory-mapped файлы через FileChannel.map.
Для неблокирующего асинхронного ввода-вывода в серверных приложениях может быть проще использовать AsynchronousFileChannel.
Выбор зависит от требований: кодировка и удобство работы с текстом, требования по памяти, производительность и блокирующее/неблокирующее поведение.
Аналоги в других языках и отличия от Java
- PHP
file_get_contents считывает весь файл в строку, fopen/fread для потокового чтения. В отличие от Java, PHP не строг типами, но те же риски OOM при чтении больших файлов.
// PHP
$content = file_get_contents('hello.txt');
echo $content;
Hello
fs.readFileSync возвращает Buffer или строку, fs.createReadStream предоставляет поток. Node.js по умолчанию асинхронен и не блокирует весь поток исполнения.
// Node.js
const fs = require('fs');
console.log(fs.readFileSync('hello.txt', 'utf8'));
Hello
open(...).read() читает всё; read(size) читает до size байт; итерация по файлу читает строки. Python проще в синтаксисе, но те же концепции: побайтовое чтение vs текстовое с декодированием.
# Python
with open('hello.txt', 'r', encoding='utf-8') as f:
print(f.read())
Hello
В SQL чтение файлов выполняется через функции СУБД (LOAD_FILE, COPY) и сильно зависит от привилегий и возможностей СУБД. Это не эквивалент методов read на уровне языка.
File.ReadAllText / File.ReadAllBytes / Stream.Read и StreamReader похожи по семантике на Java. Имеются async/await версии для асинхронного ввода-вывода.
// C#
using System.IO;
Console.WriteLine(File.ReadAllText("hello.txt"));
Hello
io.open и :read позволяют читать строки или блоки. Меньше стандартной инфраструктуры по сравнению с Java, но простая работа с файлами возможна.
-- Lua
local f = io.open('hello.txt', 'r')
print(f:read('*a'))
f:close()
Hello
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 работает поверх 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)
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
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)
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. Построчная обработка больших файлов с ограничением памяти
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. Чтение с точным числом байт в цикле
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
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)
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 заголовки
Эти примеры показывают, как применять разные механизмы чтения в реальных и редких сценариях, оптимизируя память, производительность и корректность декодирования.