Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Буферизированные потоки в Java
Буферизированные потоки - это специальные классы (BufferedInputStream, BufferedOutputStream, BufferedReader, BufferedWriter), которые оборачивают обычные потоки для повышения производительности через использование буфера в памяти.
Основная проблема
// БЕЗ буферизации: каждый вызов read() обращается к диску
public class SlowReading {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("large-file.txt");
byte[] buffer = new byte[1024];
int bytesRead;
// Каждый вызов read() = обращение к диску!
// Если файл 1 GB, это 1000000 обращений к диску
// Диск медленный: 1 операция может занять миллисекунду
// Итого: 1000000 ms = 1000 секунд!
while ((bytesRead = fis.read(buffer)) != -1) {
processData(buffer, bytesRead);
}
fis.close();
}
}
// С буферизацией: BufferedInputStream读 данные блоками
public class FastReading {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("large-file.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
// BufferedInputStream имеет внутренний буфер (обычно 8192 байта)
// Первый read() прочитает 8192 байта с диска
// Следующие 8192 read() операций будут из памяти (очень быстро)
// Затем ещё 8192 байта с диска и т.д.
// Для 1 GB: только 122880 обращений к диску вместо 1000000
// Ускорение: ~8x раз!
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = bis.read(buffer)) != -1) {
processData(buffer, bytesRead);
}
bis.close();
}
}
Как работает буферизация
БЕЗ буфера (FileInputStream):
┌──────────────────────────────┐
│ Приложение │
└──────────┬───────────────────┘
│ read()
↓
┌──────────────────────────────┐
│ Диск │ ← МЕДЛЕННО (1-10 ms)
└──────────────────────────────┘
С буфером (BufferedInputStream):
┌──────────────────────────────┐
│ Приложение │
└──────────┬───────────────────┘
│ read() из буфера
↓
┌──────────────────────────────┐
│ Буфер в памяти (8192 байта) │ ← БЫСТРО (<1 мкс)
│ когда пуст │
└──────────┬───────────────────┘
│ refill()
↓
┌──────────────────────────────┐
│ Диск │ ← МЕДЛЕННО (1-10 ms)
└──────────────────────────────┘
Результат: 99% операций из быстрого буфера!
Типы буферизированных потоков
1. BufferedInputStream (для бинарных данных)
public class BufferedInputStreamExample {
public static void main(String[] args) throws IOException {
// Оборачиваем FileInputStream
FileInputStream fis = new FileInputStream("data.bin");
BufferedInputStream bis = new BufferedInputStream(fis, 8192); // 8KB буфер
// Чтение одного байта
int byte1 = bis.read(); // Если буфер пуст, прочитает 8192 байта с диска
int byte2 = bis.read(); // Из буфера (очень быстро)
int byte3 = bis.read(); // Из буфера (очень быстро)
// Чтение массива
byte[] data = new byte[1024];
int bytesRead = bis.read(data);
bis.close();
}
}
2. BufferedOutputStream (для бинарных данных)
public class BufferedOutputStreamExample {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("output.bin");
BufferedOutputStream bos = new BufferedOutputStream(fos, 8192);
// Написание данных
byte[] data = new byte[100000];
// Вместо 100000 операций записи на диск,
// BufferedOutputStream накопит данные в буфере
// и запишет блоками по 8192 байта
bos.write(data);
// Очень важно! Flush отправляет оставшиеся данные на диск
bos.flush();
// Или close() также вызывает flush()
bos.close();
}
}
3. BufferedReader (для текстовых данных)
public class BufferedReaderExample {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("file.txt");
BufferedReader br = new BufferedReader(fr);
// Чтение построчно
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
br.close();
// BufferedReader особенно полезен для readLine()
// которая находит символы новой строки
}
}
4. BufferedWriter (для текстовых данных)
public class BufferedWriterExample {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("output.txt");
BufferedWriter bw = new BufferedWriter(fw);
// Написание текста
bw.write("Hello World");
bw.newLine();
bw.write("Second line");
bw.newLine();
// Важно: flush отправляет на диск
bw.flush();
// Или close() вызывает flush() автоматически
bw.close();
}
}
Практическое сравнение производительности
public class PerformanceComparison {
public static void main(String[] args) throws IOException {
// Создать тестовый файл 100 MB
createLargeFile("test.bin", 100 * 1024 * 1024);
// Без буферизации
long start = System.currentTimeMillis();
readWithoutBuffer("test.bin");
long unbufferedTime = System.currentTimeMillis() - start;
System.out.println("Без буфера: " + unbufferedTime + " ms");
// С буферизацией
start = System.currentTimeMillis();
readWithBuffer("test.bin");
long bufferedTime = System.currentTimeMillis() - start;
System.out.println("С буфером: " + bufferedTime + " ms");
System.out.println("Ускорение: " +
(unbufferedTime / (double)bufferedTime) + "x");
}
private static void readWithoutBuffer(String filename) throws IOException {
FileInputStream fis = new FileInputStream(filename);
int data;
while ((data = fis.read()) != -1) {
// Обработка
}
fis.close();
}
private static void readWithBuffer(String filename) throws IOException {
BufferedInputStream bis = new BufferedInputStream(
new FileInputStream(filename), 8192);
int data;
while ((data = bis.read()) != -1) {
// Обработка
}
bis.close();
}
}
// Примерный результат:
// Без буфера: 5200 ms
// С буфером: 650 ms
// Ускорение: 8x
Размер буфера
public class BufferSizing {
public static void main(String[] args) throws IOException {
// Стандартный размер буфера: 8192 байта
BufferedInputStream bis1 = new BufferedInputStream(
new FileInputStream("file.bin"));
// Пользовательский размер буфера
// Для SSD можно увеличить до 64KB
BufferedInputStream bis2 = new BufferedInputStream(
new FileInputStream("file.bin"), 65536);
// Для медленных сетевых соединений наоборот меньше
BufferedInputStream bis3 = new BufferedInputStream(
new FileInputStream("file.bin"), 4096);
bis1.close();
bis2.close();
bis3.close();
}
}
// Рекомендации:
// - HDD: 8KB - 16KB
// - SSD: 64KB - 256KB
// - Сеть: 4KB - 8KB
// - Тестировать на своих данных!
Когда использовать буферизированные потоки
Обязательно используй BufferedInputStream/OutputStream для:
// 1. Файловые операции
FileInputStream fis = new FileInputStream("huge-file.dat");
BufferedInputStream bis = new BufferedInputStream(fis);
// 2. Сетевые операции
Socket socket = serverSocket.accept();
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
// 3. Работа с архивами
ZipInputStream zis = new ZipInputStream(new FileInputStream("archive.zip"));
BufferedInputStream bis = new BufferedInputStream(zis);
// 4. Чтение большого объема данных
long largeFileSize = 1_000_000_000L; // 1 GB
Используй для малых операций:
// Для небольших файлов буферизация может быть избыточна,
// но не помешает
FileInputStream fis = new FileInputStream("small.txt"); // 1 KB
// всё ещё можно оборачивать в BufferedInputStream
Практический пример: копирование файла
public class FileCopy {
// БЕЗ буферизации - МЕДЛЕННО
public static void copySlowly(String source, String destination)
throws IOException {
FileInputStream fis = new FileInputStream(source);
FileOutputStream fos = new FileOutputStream(destination);
int data;
while ((data = fis.read()) != -1) { // Каждый байт = обращение к диску
fos.write(data);
}
fis.close();
fos.close();
}
// С буферизацией - БЫСТРО
public static void copyFast(String source, String destination)
throws IOException {
BufferedInputStream bis = new BufferedInputStream(
new FileInputStream(source));
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(destination));
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = bis.read(buffer)) != -1) {
bos.write(buffer, 0, bytesRead);
}
bos.flush();
bos.close();
bis.close();
}
// Java 9+: использовать transferTo()
public static void copyOptimal(String source, String destination)
throws IOException {
try (FileInputStream fis = new FileInputStream(source);
FileOutputStream fos = new FileOutputStream(destination)) {
fis.transferTo(fos); // Оптимизирована автоматически
}
}
}
Важно: не забывай flush() и close()
public class FlushExample {
public static void main(String[] args) throws IOException {
BufferedWriter bw = new BufferedWriter(
new FileWriter("output.txt"));
bw.write("Important data");
// Данные в буфере, ещё НЕ на диске!
bw.flush(); // Отправить данные на диск
// Теперь данные на диске, даже если программа упадёт
bw.close(); // Вызывает flush() и закрывает поток
}
}
Заключение
Буферизированные потоки - это критический инструмент для:
- Производительности - в 5-10 раз ускорение
- Масштабируемости - обработка больших файлов
- Надёжности - правильное управление ресурсами
Правило: ВСЕГДА оборачивай потоки в буферизированные версии при работе с файлами и сетью, за исключением очень малых операций.