Программирование на PHP: управление файловым хранилищем

Раздел: Программирование на PHP -> Работа с файлами

Основы файловых операций в PHP

Основной подход. Для типичных задач чтения и записи файлов небольшого размера рекомендуется использовать функции file_get_contents() и file_put_contents(). Они скрывают детали открытия и закрытия дескриптора, что уменьшает вероятность ошибок. Ниже приведён пример, который читает содержимое файла, изменяет его и записывает обратно.

<?php
$filename = 'data.txt';
$content = file_get_contents($filename);
if ($content === false) {
    echo 'Не удалось прочитать файл';
    exit;
}
$newContent = strtoupper($content);
$result = file_put_contents($filename, $newContent);
if ($result === false) {
    echo 'Не удалось записать файл';
} else {
    echo 'Успешно записано ' . $result . ' байт';
}
?>

Include system php (включение системного файла)

Пояснение. file_get_contents() возвращает строку с содержимым или false при ошибке. file_put_contents() записывает данные и возвращает количество записанных байт или false. Такая схема подходит для файлов, размер которых позволяет держать всё содержимое в оперативной памяти (обычно до десятков мегабайт).

Как прочитать файл построчно при большом объёме?

Для обработки больших файлов (логи, дампы) лучше применять построчное чтение с помощью fgets(). Файл открывается функцией fopen(), читается по одной строке, после чего дескриптор закрывается fclose(). Это позволяет экономить память.

<?php
$handle = fopen('big.log', 'r');
if ($handle === false) {
    die('Ошибка открытия файла');
}
while (($line = fgets($handle)) !== false) {
    echo $line; // обработка строки
}
fclose($handle);
?>

Ru reading php line (чтение строки из файла php)

Типичная ошибка: забыть проверить результат fopen(). Если файла не существует или нет прав на чтение, fopen вернёт false, и последующий вызов fgets приведёт к предупреждению. Всегда следует проверять дескриптор перед использованием.

Как дописать данные в конец файла без перезаписи?

Режим 'a' (append) при открытии файла позволяет добавлять новые строки, не затрагивая уже существующее содержимое. Указатель файла устанавливается в конец.

<?php
$handle = fopen('log.txt', 'a');
if ($handle) {
    fwrite($handle, date('Y-m-d H:i:s') . " - запись\n");
    fclose($handle);
}
?>

Php file get html (получение html файла через php)

Важно. Режим 'w' сначала очищает файл, а 'a' сохраняет содержимое. Для добавления на уровень байт можно использовать флаг FILE_APPEND в file_put_contents().

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

При одновременной записи из нескольких процессов возможны повреждения данных. Функция flock() устанавливает блокировку на дескриптор файла: исключительную (LOCK_EX) или разделяемую (LOCK_SH). Блокировка должна сниматься после завершения работы.

<?php
$handle = fopen('counter.txt', 'c+');
if (flock($handle, LOCK_EX)) {
    $count = (int)fread($handle, 1024);
    $count++;
    ftruncate($handle, 0);
    rewind($handle);
    fwrite($handle, (string)$count);
    fflush($handle);
    flock($handle, LOCK_UN);
}
fclose($handle);
?>

Php файловая система (работа с файловой системой в php)

Проблема: flock() не работает с файлами, открытыми через file_get_contents, так как у них нет открытого дескриптора. Для надёжной блокировки необходимо использовать fopen() и flock() совместно.

Как работать с директориями и проверять существование файлов?

Функция file_exists() проверяет, существует ли файл или папка. Для разделения случаев применяют is_file() и is_dir(). Создание директорий выполняется через mkdir() с рекурсивным флагом.

<?php
$path = '/var/storage/uploads/2025';
if (!is_dir($path)) {
    if (mkdir($path, 0755, true)) {
        echo 'Директория создана';
    } else {
        echo 'Ошибка создания';
    }
}
?>

Примечание. Третий аргумент true в mkdir() разрешает рекурсивное создание вложенных папок.

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

  • Ошибка доступа (permission denied). PHP должен иметь права на чтение/запись файла или директории. Проверьте владельца и права chmod. На сервере можно задать корректную umask.
  • Неверный путь. Используйте абсолютные пути или проверяйте относительные относительно текущей рабочей директории (getcwd()).
  • Превышение лимита памяти при чтении больших файлов. Вместо загрузки всего файла в память применяйте построчное чтение или потоковую обработку.
  • Проблемы с кодировкой. Если файл в UTF-8, но скрипт обрабатывает его как ASCII, может возникнуть искажение. Рекомендуется явно указывать кодировку при записи и читать с помощью mb_convert_encoding() при необходимости.
- Php количество файлов (подсчет количества файлов в папке в php)
- Archive php file (php: работа с архивными файлами (zip, tar))
- Php создать файл в папке (создание файла в папке в php)

Дополнительные примеры работы с файловой системой

Ниже приведены расширенные сценарии, которые помогут в реальных проектах.

Рекурсивное копирование директории

Стандартная функция copy не копирует вложенные папки. Следующий код создаёт рекурсивное копирование с сохранением структуры.

Пример
function copyDir($src, $dst) {
    $dir = opendir($src);
    @mkdir($dst, 0777, true);
    while (($file = readdir($dir)) !== false) {
        if ($file != '.' && $file != '..') {
            $srcFile = $src . DIRECTORY_SEPARATOR . $file;
            $dstFile = $dst . DIRECTORY_SEPARATOR . $file;
            if (is_dir($srcFile)) {
                copyDir($srcFile, $dstFile);
            } else {
                copy($srcFile, $dstFile);
            }
        }
    }
    closedir($dir);
}
copydir('/var/data/origin', '/var/data/backup');
echo 'Копирование завершено';
Копирование завершено

Итерация по файлам через SplFileObject

Объектно-ориентированный подход: SplFileObject позволяет работать с большими файлами как с итератором.

Пример
$file = new SplFileObject('large.csv', 'r');
$file->setFlags(SplFileObject::DROP_NEW_LINE);
foreach ($file as $lineNum => $line) {
    if ($lineNum === 0) continue; // пропуск заголовка
    $data = str_getcsv($line);
    print_r($data);
}
Array ( [0] => value1 [1] => value2 ... )

Обработка временных файлов через tmpfile

Функция tmpfile() создаёт временный файл, который автоматически удаляется при закрытии.

Пример
$fh = tmpfile();
fwrite($fh, 'временные данные');
rewind($fh);
echo stream_get_contents($fh);
fclose($fh); // файл удалён
временные данные

Работа с потоками (php://temp, php://output)

Поток php://temp хранит данные в памяти, а при превышении лимита сбрасывает на диск. Полезно для кэширования в памяти.

Пример
$stream = fopen('php://temp', 'w+');
fwrite($stream, 'текст для кэша');
rewind($stream);
$content = stream_get_contents($stream);
echo $content;
fclose($stream);
текст для кэша

Рекурсивный подсчёт размера папки

Пример
function dirSize($dir) {
    $size = 0;
    foreach (new DirectoryIterator($dir) as $item) {
        if ($item->isFile()) {
            $size += $item->getSize();
        } elseif ($item->isDir() && !$item->isDot()) {
            $size += dirSize($item->getPathname());
        }
    }
    return $size;
}
echo 'Размер папки: ' . dirSize('/var/www') . ' байт';
Размер папки: 1842378 байт

Работа с блокировками через flock и многоуровневую запись

Пример
$fl = fopen('shared.lock', 'c');
if (flock($fl, LOCK_SH)) {
    $data = file_get_contents('shared.json');
    flock($fl, LOCK_UN);
}
// Для исключительной записи
if (flock($fl, LOCK_EX)) {
    file_put_contents('shared.json', json_encode(['time' => time()]));
    flock($fl, LOCK_UN);
}
fclose($fl);

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

Работа с файловой системой в PHP - comments

En
Php файловая система (php)