Работа с файловыми потоками: чтение данных в PHP

Раздел: Файловые потоки и сокеты в PHP -> Работа с потоками в PHP

В PHP чтение содержимого файла через потоки предоставляет гибкий контроль над процессом получения данных. Потоки позволяют работать с файлами, сетевыми соединениями и другими источниками данных единообразно. В этой части рассмотрены основные варианты чтения файлов с использованием потоковых функций, от простых до более сложных, с примерами кода и разбором типичных ошибок.

Основные подходы к чтению файлов через потоки

Самый эффективный способ: file_get_contents с контекстом потока

Функция file_get_contents позволяет прочитать весь файл в одну строку. При использовании контекста потока (stream_context_create) можно задать таймауты, методы HTTP, заголовки и другие параметры. Это оптимально для файлов, которые помещаются в оперативную память.

Цель: быстрое получение содержимого небольшого или среднего файла (до десятков мегабайт). Случаи использования: чтение конфигурационных файлов, ответов API, локальных текстовых файлов.


$context = stream_context_create([
    'http' => [
        'method' => 'GET',
        'timeout' => 10
    ]
]);
$content = file_get_contents('https://example.com/data.txt', false, $context);
if ($content === false) {
    // ошибка
}
echo $content;

Php failed to open stream (ошибка открытия потока в php (failed to open stream))

Проблема: при неудачном открытии возвращается false. Необходимо явно проверять результат. Для больших файлов может не хватить памяти - используйте поточное чтение.

Как читать файл частями, контролируя размер буфера?

Вариант: fopen + fread + fclose. Открывает поток, читает блоками заданного размера, закрывает. Используется для больших файлов, когда нужно обрабатывать данные по частям (например, при передаче файла или подсчете хеша).


$handle = fopen('largefile.txt', 'rb');
if ($handle) {
    $bufferSize = 4096;
    while (!feof($handle)) {
        $chunk = fread($handle, $bufferSize);
        // обработка $chunk
    }
    fclose($handle);
}

Stream file contents php (чтение содержимого файла через поток в php)

Ошибка: если не проверять fopen, скрипт может выдать предупреждение. Также fread может вернуть меньше байт, чем запрошено - это нормально, цикл продолжается до feof.

Как обработать большой файл строка за строкой?

Вариант: fgets. Читает одну строку (до символа новой строки). Подходит для построчной обработки логов, CSV и т.д.


$handle = fopen('log.txt', 'r');
if ($handle) {
    while (($line = fgets($handle)) !== false) {
        echo $line;
    }
    fclose($handle);
}

Проблема: fgets по умолчанию читает до 4096 байт, если строка длиннее, чтение будет разбито. Явно задайте длину вторым параметром, чтобы избежать разрывов.

Как использовать объектно-ориентированный подход для чтения файла?

Вариант: SplFileObject. Класс из SPL, реализует итератор для потока. Удобен для типовых операций, совместим с foreach.


$file = new SplFileObject('data.txt', 'r');
foreach ($file as $lineNum => $line) {
    echo "Строка $lineNum: $line";
}

Ошибка: если файл не существует, выбрасывается исключение RuntimeException. Следует обрабатывать исключения или проверять существование файла.

Как получить содержимое произвольного потока (например, php://memory)?

Вариант: stream_get_contents. Функция читает остаток потока в строку. Используется после открытия любого потока (файл, сокет, временный поток).


$stream = fopen('php://memory', 'rb+');
fwrite($stream, 'Test data');
rewind($stream);
$content = stream_get_contents($stream);
fclose($stream);
echo $content;

Проблема: если указатель не на начале, прочитается только часть. Перед вызовом stream_get_contents следует перемотать поток с помощью rewind или fseek.

Как прочитать тело HTTP-запроса как поток?

Вариант: чтение из встроенного потока php://input. Используется для получения необработанных данных POST-запроса (например, JSON). Работает как поток только для чтения.


$rawData = file_get_contents('php://input');
$json = json_decode($rawData, true);

Ошибка: php://input доступен только для запросов с Content-Type application/x-www-form-urlencoded или multipart/form-data не для POST с типом multipart (в этом случае используйте $_POST). Для больших данных может быть недоступен при некоторых настройках сервера.

Расширенные примеры работы с файловыми потоками

В этом разделе приведены нестандартные сценарии использования потоков для чтения файлов, включая фильтрацию, прогресс-бары и пользовательские обработчики.

Пример 1. Чтение большого файла с отображением прогресса

Используется fopen + fread с выводом процента выполнения. Длина файла определяется через fstat.

Пример

$handle = fopen('bigfile.dat', 'rb');
if ($handle) {
    $stat = fstat($handle);
    $total = $stat['size'];
    $readBytes = 0;
    $bufferSize = 8192;
    while (!feof($handle)) {
        $data = fread($handle, $bufferSize);
        $readBytes += strlen($data);
        $percent = round($readBytes * 100 / $total);
        echo "\rПрочитано: $percent%";
        // обработка $data
    }
    fclose($handle);
    echo "\nГотово.";
}
Прочитано: 45%
Прочитано: 100%
Готово.

Пример 2. Применение потокового фильтра (конвертация кодировки)

Чтение файла в UTF-8 с автоматической конвертацией из Windows-1251 с помощью фильтра convert.iconv.

Пример

$handle = fopen('file_win1251.txt', 'rb');
stream_filter_append($handle, 'convert.iconv.windows-1251/utf-8');
while (($line = fgets($handle)) !== false) {
    echo $line;
}
fclose($handle);
(Строки в UTF-8)

Пример 3. Чтение удаленного файла через HTTP с обработкой редиректов

Используется stream_context_create с параметрами follow_location и max_redirects.

Пример

$options = [
    'http' => [
        'follow_location' => 1,
        'max_redirects' => 5,
        'timeout' => 30
    ]
];
$context = stream_context_create($options);
$content = file_get_contents('http://example.com/redirecting-file', false, $context);
if ($content !== false) {
    echo 'Длина: ' . strlen($content) . ' байт';
}
Длина: 12345 байт

Пример 4. Чтение из пользовательского потока (создание обертки streamWrapper)

Регистрация собственной обертки для чтения данных из базы данных как потока. Упрощенная реализация.

Пример

class DBStream {
    protected $data;
    protected $position;
    public function stream_open($path, $mode, $options, &$opened_path) {
        // извлекаем данные из БД
        $this->data = 'Data from database';
        $this->position = 0;
        return true;
    }
    public function stream_read($count) {
        $chunk = substr($this->data, $this->position, $count);
        $this->position += strlen($chunk);
        return $chunk;
    }
    public function stream_eof() {
        return $this->position >= strlen($this->data);
    }
    public function stream_stat() {
        return ['size' => strlen($this->data)];
    }
}
stream_wrapper_register('db', 'DBStream');
$content = file_get_contents('db://query');
echo $content;
Data from database

Пример 5. Комбинированное чтение: частичное с пропуском байтов

Чтение 100 байт, начиная с 50 позиции, с помощью fseek и fread.

Пример

$handle = fopen('file.txt', 'rb');
fseek($handle, 50);
$chunk = fread($handle, 100);
echo $chunk;
(Символы с 51 по 150)

Пример 6. Использование stream_copy_to_stream для копирования между потоками

Копирование содержимого одного файла в другой через потоки без загрузки в память.

Пример

$src = fopen('source.txt', 'rb');
$dst = fopen('destination.txt', 'wb');
$copiedBytes = stream_copy_to_stream($src, $dst);
fclose($src);
fclose($dst);
echo "Скопировано $copiedBytes байт";
Скопировано 2048 байт

Чтение содержимого файла через поток в PHP - comments

En
Stream file contents php (php)