fopen(file,w+) обрезает файл, прежде чем я смогу проверить, заблокирован ли он с помощью flock()

У меня есть функция, которая получает имя файла и объект json для записи в текстовый файл.

Объект обновляется и должен полностью заменить текущее содержимое файла. У каждого посетителя сайта есть свой файл. Множественные быстрые изменения создают ситуацию, когда файл усекается на fopen(file,w+), а затем не записывается, поскольку он заблокирован. Конечный результат - пустой файл.

Я уверен, что есть стандартный простой способ сделать это, поскольку это такая обычная деятельность. В идеале я ищу способ проверить, есть ли у файла блокировка, прежде чем обрезать файл с помощью fopen в режиме w+ или способ переключения режимов.

Кажется странным, что вам пришлось бы обрезать файл с помощью fopen(), чтобы получить дескриптор файла для передачи в flock(), чтобы проверить, заблокирован ли он - но вы только что усекли его, так в чем смысл?

Вот функция, которая у меня есть до сих пор:

function updateFile($filename, $jsonFileData) {
    $fp = fopen($filename,"w+");
    if (flock($fp, LOCK_EX)) {  
        fwrite($fp, $jsonFileData);
        flock($fp, LOCK_UN);
        fclose($fp);
        return true;
    } else {
        fclose($fp);
        return false;
    }
}

person Peter Oram    schedule 23.10.2012    source источник
comment
И почему вы не используете базу данных для этого?   -  person NullUserException    schedule 24.10.2012
comment
Взял проект от другого, уже работающего с файлами. Вместо этого можно было бы перекодировать его для работы с базой данных, но попытаться посмотреть, есть ли другое решение, прежде чем переделывать все это.   -  person Peter Oram    schedule 24.10.2012


Ответы (1)


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

$fp = fopen("/tmp/lock.txt", "c");

if (flock($fp, LOCK_EX)) {  // acquire an exclusive lock
    ftruncate($fp, 0);      // truncate file
    fwrite($fp, "Write something here\n");
    fflush($fp);            // flush output before releasing the lock
    flock($fp, LOCK_UN);    // release the lock
} else {
    echo "Couldn't get the lock!";
}

fclose($fp);

Полное описание режима "c":

Откройте файл для записи. Если файл не существует, он создается. Если он существует, он не усекается (в отличие от 'w'), и вызов этой функции не завершается ошибкой (как в случае с 'x'). Указатель файла располагается в начале файла. Это может быть полезно, если требуется получить рекомендательную блокировку (см. flock()) перед попыткой изменить файл, поскольку использование 'w' может обрезать файл до того, как будет получена блокировка (если требуется усечение, после запроса блокировки можно использовать ftruncate()).

Не похоже, что вам это нужно, но есть и соответствующий режим "c+", если вы хотите и читать, и писать.

person John Kugelman    schedule 23.10.2012