Работа с файлами на PHP: от основ до продвинутых приёмов
Основные функции работы с файлами в PHP
Как наиболее эффективно прочитать или записать файл целиком?
Для небольших файлов (до нескольких мегабайт) оптимальным решением являются функции file_get_contents() и file_put_contents(). Они выполняют чтение и запись за один вызов, автоматически открывая и закрывая файл.
$content = file_get_contents('data.txt'); // чтение
file_put_contents('output.txt', 'Новый текст'); // запись
Цель: быстрое копирование, чтение конфигурационных файлов, работа с текстовыми данными небольшого объёма.
Проблема: при очень больших файлах (сотни мегабайт) эти функции могут вызвать переполнение памяти. Решение: использовать построчное чтение через fgets() или потоковую обработку.
Как читать файл построчно для обработки больших объёмов данных?
Когда файл слишком велик для одномоментной загрузки в память, используют fopen() в связке с fgets().
$handle = fopen('bigfile.log', 'r');
if ($handle) {
while (($line = fgets($handle)) !== false) {
// обработка строки
echo $line;
}
fclose($handle);
} else {
echo 'Ошибка открытия файла';
}
Цель: обработка логов, импорт данных, чтение CSV.
Проблемы: не забыть проверить успешность открытия (fopen() возвращает false при ошибке). После цикла обязательно закрыть файл (fclose()), иначе будут утечки ресурсов.
Как записать данные с контролем позиции и блокировкой?
Функции fwrite() и flock() позволяют управлять записью и предотвращать конфликты при параллельном доступе.
$handle = fopen('counter.txt', 'c+');
flock($handle, LOCK_EX); // эксклюзивная блокировка
fwrite($handle, '1');
fflush($handle);
flock($handle, LOCK_UN); // снятие блокировки
fclose($handle);
Цель: логирование с блокировкой, файлы счётчиков, файлы конфигурации при многопоточном доступе.
Как прочитать файл в массив строк?
Функция file() читает весь файл и возвращает массив строк (с сохранением символов новой строки).
$lines = file('data.txt');
foreach ($lines as $lineNum => $line) {
echo "Строка $lineNum: $line";
}
Цель: быстрая загрузка файла для построчной обработки, если объём позволяет.
Как проверить существование и права доступа к файлу?
Используйте file_exists(), is_readable(), is_writable().
$filename = 'config.php';
if (file_exists($filename) && is_readable($filename)) {
include $filename;
} else {
echo 'Файл не найден или недоступен для чтения';
}
Цель: безопасное включение файлов, проверка перед операциями.
Проблема: file_exists() кэширует результаты, для свежей проверки используйте clearstatcache().
Как скопировать, переместить или удалить файл?
Функции copy(), rename(), unlink().
$old = 'temp.txt';
$new = 'backup/temp.txt';
if (copy($old, $new)) {
echo 'Файл скопирован';
}
rename($new, 'archive/temp.txt'); // перемещение/переименование
unlink('temp.txt'); // удаление
Цель: управление файлами на диске.
Ошибки: copy() не создаёт директории автоматически; rename() может не работать между разными файловыми системами; unlink() удаляет безвозвратно.
Как создать директорию и получить список файлов?
Для создания каталога используется mkdir(), для получения содержимого - scandir() или glob().
mkdir('new_folder', 0755, true); // true - рекурсивное создание
$files = scandir('.');
foreach ($files as $file) {
if ($file != '.' && $file != '..') {
echo $file."\n";
}
}
// glob позволяет фильтровать
$phpFiles = glob('*.php');
print_r($phpFiles);
Цель: работа с каталогами, обход файловой системы.
Проблема: mkdir() может не создать промежуточные директории без флага true. scandir() возвращает точки, их нужно отфильтровывать.
Как работать с CSV-файлами?
Специализированные функции fgetcsv() и fputcsv() упрощают чтение и запись CSV.
$handle = fopen('data.csv', 'r');
while (($row = fgetcsv($handle, 1000, ',')) !== false) {
// $row - массив полей
print_r($row);
}
fclose($handle);
$out = fopen('new.csv', 'w');
fputcsv($out, ['Имя', 'Возраст'], ';');
fclose($out);
Цель: импорт/экспорт табличных данных.
Проблема: кодировка. Если файл не в UTF-8, данные могут отображаться некорректно. Используйте iconv() или mb_convert_encoding().
Как добавить данные в конец файла?
Флаг FILE_APPEND в file_put_contents() или режим a в fopen().
file_put_contents('log.txt', 'Новая запись\n', FILE_APPEND);
// или
$fp = fopen('log.txt', 'a');
fwrite($fp, 'Другая запись\n');
fclose($fp);
Цель: ведение логов, журналов.
Расширенные примеры использования файловых функций
Пример 1: Построчное чтение большого лог-файла с фильтрацией
Предположим, что лог-файл размером 2 ГБ содержит строки с уровнем ошибок. Необходимо выбрать только строки с 'ERROR'.
$handle = fopen('server.log', 'r');
if (!$handle) { die('Не удалось открыть файл'); }
$output = fopen('errors.log', 'w');
while (($line = fgets($handle)) !== false) {
if (strpos($line, 'ERROR') !== false) {
fwrite($output, $line);
}
}
fclose($handle);
fclose($output);
echo 'Готово. Отфильтрованные ошибки записаны в errors.log.';
Результат: создается файл errors.log с отфильтрованными строками. Потребление памяти минимально.
Пример 2: Работа с бинарными файлами (чтение изображения)
Чтение первых нескольких байт PNG для проверки сигнатуры.
$handle = fopen('image.png', 'rb');
$header = fread($handle, 8);
$expected = "\x89PNG\r\n\x1a\n";
if ($header === $expected) {
echo "Это PNG-файл.";
} else {
echo "Неизвестный тип файла.";
}
fclose($handle);
Результат: 'Это PNG-файл.' или 'Неизвестный тип файла.'
Пример 3: Запись CSV с экранированием и управлением кодировкой
Запись данных в UTF-8 с разделителем ';', фильтр для экспорта из массива.
$data = [
['Иван', 'Иванов', 30],
['Мария', 'Петрова', 25],
];
$handle = fopen('users.csv', 'w');
// BOM для корректного отображения UTF-8 в Excel
fwrite($handle, "\xEF\xBB\xBF");
foreach ($data as $row) {
fputcsv($handle, $row, ';', '"');
}
fclose($handle);
echo 'CSV файл создан.';
Результат: файл users.csv с корректными данными, открывается в Excel без искажений.
Пример 4: Использование потоковых фильтров (чтение gzip-архива)
Чтение сжатого файла на лету без распаковки на диск.
$filename = 'data.log.gz';
$handle = fopen('compress.zlib://'.$filename, 'r');
if ($handle) {
while (($line = fgets($handle)) !== false) {
echo $line;
}
fclose($handle);
}
Результат: содержимое сжатого файла выводится построчно.
Пример 5: Произвольный доступ с fseek, ftell и rewind
Чтение определённого блока данных в середине файла, например, 10 байт начиная с 100-го.
$file = 'data.bin';
$handle = fopen($file, 'rb');
fseek($handle, 100); // перемещаем указатель на 100 байт от начала
$bytes = fread($handle, 10);
echo 'Прочитано: ' . bin2hex($bytes);
echo '\nТекущая позиция: ' . ftell($handle);
rewind($handle); // возврат в начало
fclose($handle);
Результат: вывод шестнадцатеричного представления 10 байт и позиции 110.
Пример 6: Временные файлы (tmpfile)
Создание временного файла, который автоматически удаляется после закрытия.
$temp = tmpfile();
fwrite($temp, 'Временные данные');
rewind($temp);
echo fread($temp, 1024);
fclose($temp); // файл удаляется
Результат: вывод 'Временные данные', файл не остаётся на диске.
Пример 7: Рекурсивный обход директорий с помощью RecursiveDirectoryIterator
Вывод всех PHP-файлов в проекте.
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator('.')
);
foreach ($iterator as $file) {
if ($file->getExtension() === 'php') {
echo $file->getPathname() . "\n";
}
}
Результат: список всех файлов .php в текущей директории и поддиректориях.
Пример 8: Обработка ошибок с исключениями (SplFileObject)
Использование SPL-классов для более удобной работы с файлами и обработки исключений.
try {
$file = new SplFileObject('nonexistent.txt');
while (!$file->eof()) {
echo $file->fgets();
}
} catch (RuntimeException $e) {
echo 'Ошибка: ' . $e->getMessage();
}
Результат: 'Ошибка: SplFileObject::__construct(nonexistent.txt): failed to open stream: No such file or directory'