FileInputStream: примеры (JAVA)
FileInputStream(File file, String name)Класс FileInputStream - назначение и сигнатуры
Класс FileInputStream предоставляет байтовый поток для чтения содержимого файлов. Применяется для работы с бинарными файлами, когда требуется низкоуровневое чтение байтов, а также при совместной работе с NIO-каналами. Поток возвращает либо отдельный байт в виде int (0..255), либо количество прочитанных байтов при чтении в массив. В случае конца файла метод чтения возвращает -1 или 0 в соответствующих перегрузках.
Основные конструкторы и их параметры:
FileInputStream(File file) FileInputStream(String name) FileInputStream(FileDescriptor fdObj)
Пояснения к аргументам:
- File - объект из java.io.File, указывающий путь; может вызвать
FileNotFoundException, если файл отсутствует. - String - строка с путём до файла; поведение аналогично.
- FileDescriptor - дескриптор открытого файла (например,
FileDescriptor.in,.out,.err).
Основные методы и окончания их значений:
int read() throws IOException // один байт, -1 при EOF int read(byte[] b) throws IOException // количество байт или -1 int read(byte[] b, int off, int len) throws IOException void close() throws IOException int available() throws IOException // оценка доступных байт long skip(long n) throws IOException FileChannel getChannel() FileDescriptor getFD() throws IOException // с Java 9 унаследованы: byte[] readAllBytes(), int readNBytes(byte[] b, int off, int len), long transferTo(OutputStream out)
Возвращаемые значения обычно представляют собой количество прочитанных байт или одиночный байт. В случае ошибок генерируются исключения IOException или более конкретные FileNotFoundException. Поток реализует Closeable и поддерживает конструкцию try-with-resources.
Короткие примеры использования
1) Чтение файла по одному байту:
import java.io.*;
public class ReadByteByByte {
public static void main(String[] args) throws Exception {
try (FileInputStream fis = new FileInputStream("example.txt")) {
int b;
while ((b = fis.read()) != -1) {
System.out.print((char) b);
}
}
}
}
Результат (если в example.txt текст "Hello\n"): Hello
2) Чтение в буфер:
import java.io.*;
public class ReadWithBuffer {
public static void main(String[] args) throws Exception {
try (FileInputStream fis = new FileInputStream("example.bin")) {
byte[] buf = new byte[8];
int n;
while ((n = fis.read(buf)) != -1) {
System.out.println("Прочитано байт: " + n);
}
}
}
}
Пример вывода: Прочитано байт: 8 Прочитано байт: 3
3) Использование readAllBytes (Java 9+):
import java.io.*;
public class ReadAllBytesExample {
public static void main(String[] args) throws Exception {
try (FileInputStream fis = new FileInputStream("text.txt")) {
byte[] all = fis.readAllBytes();
System.out.println(new String(all));
}
}
}
Результат: содержимое файла как строка
4) Ошибка при отсутствии файла:
import java.io.*;
public class NotFound {
public static void main(String[] args) throws Exception {
new FileInputStream("missing.file");
}
}
Исключение:
java.io.FileNotFoundException: missing.file (No such file or directory)
at java.base/java.io.FileInputStream.open0(Native Method)
...
Аналоги в Java и их особенности
- BufferedInputStream - добавляет буферизацию над FileInputStream, улучшает производительность при частом чтении маленьких блоков.
- FileReader - символьный поток, подходит для текстовых файлов с преобразованием кодировок; если требуются байты, предпочтительнее FileInputStream.
- Files.newInputStream(Path) (NIO.2) - более гибкий способ открытия потока с опциями; удобен при работе с Path и атрибутами.
- RandomAccessFile - поддерживает чтение и запись в произвольных позициях; полезен при необходимости позиционирования и записи.
- FileChannel - для высокопроизводительных операций, передачи данных между каналами и memory-mapped файлов; используется через getChannel().
- ByteArrayInputStream - для тестов и чтения из памяти.
Выбор зависит от задач: для текстовых файлов лучше FileReader или java.nio.file.Files; для больших бинарных потоков и копирования - FileChannel/transferTo; для простого побайтного чтения без буфера - FileInputStream.
Аналоги в других языках и отличия
PHP (функции fopen/fread):
$f = fopen('file.bin', 'rb');
$data = fread($f, 1024);
fclose($f);
Результат: массив байтов в строковом виде или бинарная строка
JavaScript (Node.js):
const fs = require('fs');
const buf = fs.readFileSync('file.bin');
console.log(buf.length);
Вывод: количество байт, например 1234
Python:
with open('file.bin', 'rb') as f:
data = f.read(1024)
print(len(data))
Вывод: число прочитанных байт
C#:
using (var fs = new FileStream("file.bin", FileMode.Open))
{
byte[] buf = new byte[1024];
int n = fs.Read(buf, 0, buf.Length);
}
Результат: n - число прочитанных байт
Go:
f, _ := os.Open("file.bin")
buf := make([]byte, 1024)
n, _ := f.Read(buf)
n - количество байт
Kotlin (использует JVM-классы или удобные расширения):
val fis = java.io.FileInputStream("file.bin")
val bytes = fis.readBytes()
bytes - ByteArray со всем содержимым
Lua:
local f = io.open('file.bin', 'rb')
local data = f:read(1024)
f:close()
data - бинарная строка или nil при EOF
SQL (извлечение BLOB через JDBC):
ResultSet rs = stmt.executeQuery("SELECT data FROM files WHERE id=1");
if (rs.next()) {
InputStream in = rs.getBinaryStream(1);
// далее чтение как из FileInputStream
}
Результат: InputStream для BLOB, чтение аналогично чтению из файла
Отличия: в разных языках API различается по синхронности, обработке ошибок и представлению байтов. Java предоставляет тесную интеграцию с NIO и Channel, а ряд языков предлагают более высокоуровневые утилиты для чтения целиком в память.
Типичные ошибки и их проявления
1) Отсутствие файла - FileNotFoundException:
new FileInputStream("no_such.file");
java.io.FileNotFoundException: no_such.file (No such file or directory)
2) Чтение после закрытия - IOException:
FileInputStream fis = new FileInputStream("a.txt");
fis.close();
fis.read();
java.io.IOException: Stream closed
3) Неправильные параметры read(byte[], off, len) - IndexOutOfBoundsException:
byte[] b = new byte[10];
fis.read(b, -1, 5);
java.lang.IndexOutOfBoundsException
4) Утечка ресурсов при отсутствии закрытия - исчерпание дескрипторов, особенно при массовом открытии файлов. Решение: try-with-resources или явный finally с close().
5) Неправильная трактовка кодировки при чтении текста как байтов. Для текстовых данных применимость FileInputStream ограничена: лучше использовать Reader с указанием кодировки.
Изменения и рекомендации в современных версиях Java
- Java 7: поддержка try-with-resources, класс реализует Closeable и удобно закрывается автоматически.
- Java 9: в абстрактном классе InputStream добавлены удобные методы
readAllBytes(),readNBytes(...)иtransferTo(OutputStream). FileInputStream наследует эти возможности, что упрощает чтение и копирование. - NIO интеграция: FileInputStream предоставляет
getChannel()для получения FileChannel (добавлено ранее), при этом для высокопроизводительных операций часто рекомендуется прямо использовать java.nio.channels.FileChannel или java.nio.file.Files. - Прямых устареваний или удаления FileInputStream в актуальных релизах нет; при этом для общего использования рекомендуется API java.nio.file для гибкости и расширенных опций.
Расширенные и необычные варианты использования
1) Копирование файла «по-нулю» с помощью transferTo (эффективно для больших файлов):
import java.io.*;
import java.nio.channels.FileChannel;
public class ZeroCopyCopy {
public static void main(String[] args) throws Exception {
try (FileInputStream fis = new FileInputStream("big.bin");
FileOutputStream fos = new FileOutputStream("big_copy.bin")) {
FileChannel inCh = fis.getChannel();
FileChannel outCh = fos.getChannel();
long pos = 0;
long size = inCh.size();
while (pos < size) {
pos += inCh.transferTo(pos, size - pos, outCh);
}
System.out.println("Скопировано байт: " + size);
}
}
}
Скопировано байт: 104857600
2) Вычисление SHA-256 с помощью DigestInputStream:
import java.io.*;
import java.security.*;
import javax.xml.bind.DatatypeConverter;
public class HashFile {
public static void main(String[] args) throws Exception {
MessageDigest md = MessageDigest.getInstance("SHA-256");
try (FileInputStream fis = new FileInputStream("file.bin");
DigestInputStream dis = new DigestInputStream(fis, md)) {
byte[] buf = new byte[8192];
while (dis.read(buf) != -1) { }
}
byte[] digest = md.digest();
System.out.println(DatatypeConverter.printHexBinary(digest).toLowerCase());
}
}
Пример: e3b0c44298fc1c149afbf4c8996fb92427ae41e4...
3) Чтение фиксированного диапазона: комбинация skip + readNBytes (Java 9+):
try (FileInputStream fis = new FileInputStream("video.mp4")) {
long offset = 1024 * 1024; // 1 MB
fis.skip(offset);
byte[] segment = fis.readNBytes(4096);
System.out.println("Прочитано сегмент байт: " + segment.length);
}
Прочитано сегмент байт: 4096
4) Использование FileInputStream с FileDescriptor для чтения из стандартного ввода:
import java.io.*;
public class ReadFromStdin {
public static void main(String[] args) throws Exception {
try (FileInputStream fis = new FileInputStream(FileDescriptor.in)) {
byte[] b = new byte[64];
int n = fis.read(b);
System.out.println("Введено байт: " + n);
}
}
}
При вводе "hello": Введено байт: 6 (включая символ перевода)
5) Параллельное чтение небольших фрагментов при помощи нескольких RandomAccessFile/Channels вместо FileInputStream; для частых произвольных доступов FileInputStream мало годится, потому что он не предоставляет произвольного позиционирования напрямую.
6) Обработка больших потоков с контролем скорости: чтение блоками и паузами, использование ScheduledExecutor для лимитирования скорости передачи, при этом FileInputStream используется как источник данных.
Пояснения: приведённые примеры демонстрируют, как сочетать возможности FileInputStream с NIO и криптографическими утилитами для эффективной и безопасной работы с файлами.