Изменение файлов на PHP: от простых замен до сложных манипуляций

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

Обзор методов изменения файлов

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

Основной способ: чтение-замена-запись

$file = 'example.txt';
$content = file_get_contents($file);
$newContent = str_replace('старый текст', 'новый текст', $content);
file_put_contents($file, $newContent);

Этот подход подходит для файлов размером до нескольких десятков мегабайт. Он прост и не требует управления файловыми указателями.

Возможные проблемы:

  • Если файл не существует, file_get_contents вернёт false. Необходима проверка.
  • При конкурентном доступе может возникнуть состояние гонки. Рекомендуется блокировать файл с помощью flock.
  • Для больших файлов может не хватить памяти. Тогда следует использовать построчную обработку.

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

Если требуется заменить, например, третью строку файла, можно использовать функцию file(), которая возвращает массив строк.

$lines = file('config.txt'); // строки с символами перевода строки
$lines[2] = "новое значение\n"; // замена 3-й строки (индекс 2)
file_put_contents('config.txt', implode('', $lines));

Примечание:

индексация начинается с 0. Символы новой строки сохраняются, поэтому при записи их не нужно добавлять дополнительно, если они уже есть в элементах массива.

Ошибка: использование file() без параметра FILE_IGNORE_NEW_LINES оставляет символы перевода строки. Если требуется удалить их, следует указывать флаг или обрабатывать строки.

Как изменить файл большого размера, не загружая его целиком в память?

Для больших файлов (гигабайты) применяется построчное чтение из исходного файла и запись во временный файл. Затем исходный файл заменяется временным.

$src = fopen('bigfile.txt', 'r');
$tmp = fopen('bigfile.tmp', 'w');
while (($line = fgets($src)) !== false) {
    $line = str_replace('старое', 'новое', $line);
    fwrite($tmp, $line);
}
fclose($src);
fclose($tmp);
rename('bigfile.tmp', 'bigfile.txt');

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

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

Как добавить данные в начало или середину файла?

Вставка в начало или произвольную позицию не поддерживается напрямую. Необходимо переписать файл целиком. Например, добавление строки в начало:

$content = file_get_contents('file.txt');
$content = "Новая первая строка\n" . $content;
file_put_contents('file.txt', $content);

Для вставки в середину можно разбить содержимое на части.

Для больших файлов такой подход неэффективен. Следует создавать новый файл и копировать данные, вставляя нужный блок.

Как модифицировать INI-файл?

INI-файлы можно читать с помощью parse_ini_file, изменять массив и записывать обратно. Для записи требуется собственная функция или использование file_put_contents с форматированием.

$config = parse_ini_file('config.ini', true);
$config['database']['host'] = 'newhost';
// функция записи INI
function write_ini_file($path, $data) {
    $content = '';
    foreach ($data as $section => $values) {
        $content .= "[$section]\n";
        foreach ($values as $key => $val) {
            $content .= "$key = \"$val\"\n";
        }
    }
    file_put_contents($path, $content);
}
write_ini_file('config.ini', $config);

Ошибки: некорректная обработка кавычек, пробелов, комментариев. Реализация может быть упрощённой; для production рекомендуется использовать специализированные библиотеки.

Как выполнить замену по регулярному выражению?

Функция preg_replace позволяет заменить все вхождения, соответствующие шаблону. Это полезно для массового редактирования.

$content = file_get_contents('page.html');
$content = preg_replace('/(.*?)<\/oldTag>/s', '$1', $content);
file_put_contents('page.html', $content);

Проблемы: необходимо правильно экранировать шаблон. Неверное регулярное выражение может привести к ошибке или нежелательным заменам.

Расширенные примеры изменения файлов

Пример 1. Замена с подсчётом количества замен

Использование preg_replace_callback для подсчёта и замены.

Пример
$file = 'data.txt';
$content = file_get_contents($file);
$count = 0;
$newContent = preg_replace_callback('/pattern/', function($matches) use (&$count) {
    $count++;
    return 'replacement';
}, $content);
file_put_contents($file, $newContent);
echo "Заменили: $count";
Заменили: 5

Пример 2. Сохранение прав доступа после изменения

После записи файла часто теряются его права. Можно сохранить их до изменения.

Пример
$file = 'script.php';
$perms = fileperms($file) & 0777;
$content = file_get_contents($file);
$content = str_replace('old', 'new', $content);
file_put_contents($file, $content);
chmod($file, $perms);
(права файла сохранены)

Пример 3. Безопасная запись с блокировкой

Для исключения параллельного доступа используется flock.

Пример
$file = 'counter.txt';
$data = file_get_contents($file);
$data++;
$fp = fopen($file, 'w');
if (flock($fp, LOCK_EX)) {
    ftruncate($fp, 0);
    fwrite($fp, $data);
    flock($fp, LOCK_UN);
}
fclose($fp);
(файл обновлён, блокировка активна)

Пример 4. Изменение определённого поля в CSV

Предположим, CSV-файл с разделителем запятая; требуется изменить второе поле в строках, где первое поле равно 'id=10'.

Пример
$rows = file('data.csv');
foreach ($rows as &$row) {
    $fields = str_getcsv($row);
    if ($fields[0] == 'id=10') {
        $fields[1] = 'newvalue';
        $row = implode(',', $fields) . "\n";
    }
}
file_put_contents('data.csv', implode('', $rows));
(CSV обновлён)

Пример 5. Использование SplFileObject для больших файлов

SplFileObject предоставляет объектно-ориентированный доступ с итерацией.

Пример
$file = new SplFileObject('big.txt', 'r+');
$file->setFlags(SplFileObject::DROP_NEW_LINE);
$newLines = [];
foreach ($file as $line) {
    $newLines[] = str_replace('x', 'y', $line);
}
$file->ftruncate(0);
$file->rewind();
foreach ($newLines as $line) {
    $file->fwrite($line . "\n");
}
(большой файл обработан)

Изменение файлов в PHP - comments

En
Php файлы изменение (php)