Программирование на 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()при необходимости.
Дополнительные примеры работы с файловой системой
Ниже приведены расширенные сценарии, которые помогут в реальных проектах.
Рекурсивное копирование директории
Стандартная функция 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);
Применение разделяемых блокировок позволяет многим процессам читать файл одновременно, а запись требует исключительной блокировки.