Чтение и запись в файл.

vikm

Новичок
Чтение и запись в файл.

Приветствую всех!
Я начинающий и только изучаю PHP, так что прошу не пинать сильно.
Есть такой вот код:
PHP:
$file = "count.txt"; 
   
if(!file_exists($file))      
  fclose(fopen($file,"w+")); 
    
$fh = fopen($file,"r+");    
$cnt = fread($fh,sizeof($file));   
fclose($fh);    

//$cnt = file_get_contents($file);        

$cnt++;        

$fh = fopen($file,"w+");    
fwrite($fh,$cnt);    
fclose($fh);        

echo $cnt;
Переменная cnt увеличивается до 10 и потом сбрасывается на 2 и увеличивается дальше, снова до 10 и все повторяется. При этом если считывать файл через функцию file_get_contents(), то все работает нормально. В чем ошибка?

-~{}~ 21.09.08 12:21:

Уже разобрался,нужно написать:
PHP:
$cnt = fread($fh,filesize($file));
 

Nicholas

Новичок
Можно написать гораздо короче

PHP:
$file = "count.txt";

$cnt = is_file($file) ? (int)file_get_contents($file) : 0;

file_put_contents($file, ++$cnt);

echo $cnt;
[php]

PS Я просто хочу сказать, уходите от морально устаревших fopen, fread, fclose
а пользуйтесь file_get_contents, file_put_contents.
 

dimagolov

Новичок
Nicholas, по твоему идея считывать файл в память по частям морально устарела?
 

HraKK

Мудак
Команда форума
как по мне морально устарели программисты у которых морально устарели
-~{}~ 21.09.08 14:50:

vikm
fclose(fopen($file,"w+"));
заместо этого лучше использовать touch
 

dimagolov

Новичок
vikm, не обязательно задавать точный объем сколько считывать. задавай 4096, больше чем есть в файле все равно не прочитает, при нормальном развитии событий у тебя там всегда не больше 20 байт будет.
 

Nicholas

Новичок
HraKK, dimagolov
Приведите, пожалуйста, хоть 3 причины, почему fopen удобнее file_put(get)_contents?


Я отлично понимаю, что file_put_contents является заменой конструкции fopen(), fwrite() и fclose(), но работает при этом чуть быстрее.
Пример:
PHP:
$file = "count.txt";

$_t = microtime(true);
for ($i = 0; $i < 100000; ++$i) 
{
  file_put_contents($file, ++$i);
}
echo round(microtime(true) - $_t, 5) . '<br>';

$_t = microtime(true);
for ($i = 0; $i < 100000; ++$i) 
{
  $fp = fopen($file, 'w');
  fwrite($fp, ++$i);
  fclose($fp);
}
echo round(microtime(true) - $_t, 5) . '<br>';
Выведет:
14.51543
17.75171

А file_get_contents считывает файл по кускам. (Читайте мануалы, они рулез).
Ну или делает что-то подобное =)
Данная функция идентична функции file() с той только разницей, что содержимое файла возвращается в строке, начиная с указанного смещения offset и до maxlen байтов.
Да и по тестам file_get_contents быстрее чем fopen(), fread(), fclose().
И ГОРАЗДО быстрее чем file().

У вас есть доводы против?
 

dimagolov

Новичок
довод один - блочное чтение с помощью file_get_contents это маразм, так как каждый раз будет файл открываться и закрываться. а если не блочное, то легко можно попасть, если файл больше, чем доступно скрипту памяти.
 

Beavis

Banned
Nicholas
считай с помощью file_get_contents несколько-гигабайтный файл =))
 

edwardgorbachev

Новичок
Nicholas
Простой пример, если надо распарсить большой XML-файл, то могут возникнуть трудности при ограничении в памяти.
 

Crys

Двинутый новичок
Ничего не понимаю. Вроде бы у ТС в файле тока пара циферок может быть. Причем тут XML и несколько-гигабайтные файлы?
 

dimagolov

Новичок
Crys, при том, что такие ситуации, как в этой теме, это исключения. чаще происходит обратное - файлы не вмещаются в память целиком. новички начав "для удобства" экономить на 2-х вызовах fopen & fclose так и продолжают писать дальше, пока скрипт не валиться по лимиту памяти. Nicholas же не говорил "в этой задаче удобнее пользовать file_get_contents". Он претендовал на то, что для ВСЕХ случаев file_get_contents лучшая альтернатива fopen/fread/fclose, которые якобы морально устарели, что есть глупость.
 

kruglov

Новичок
Ммм, а проблему одновременного доступа двух скриптов к файлу решать будем? Когда один начал писать, а другой в этот момент начал читать, прочитал 0 и ага...
 

Nicholas

Новичок
Вопрос.
А должен ли php скрипт работать с большими файлами?
На мой взгляд, это будет происходить в 2-х случаях.
- парсинг большого xml файла (допустим для интернет магазина)
- восстановление бэкапа БД.
Больше применения больших файлов не нахожу.
И не является ли работа с большими файлами, ошибкой логики программы?

kruglov
все как обычно, LOCK_EX используем =)
 

Crys

Двинутый новичок
Больше применения больших файлов не нахожу.
Эх... а база geoip? Там файлик на двадцать метров... А обработка логов апача? Да и другие логи тоже... Приходилось парсить и более, чем на 100МБ файлы

Что-то какая-то тема все-таки мутная. Разговор ни о чем :)
 

SiMM

Новичок
> пользуйтесь file_get_contents, file_put_contents
Оно ещё и файлы лочит?
PHP:
<?php
$fp = dirname(__FILE__).'/cnt.txt';
if ($fp = fopen($fp,file_exists($fp) ? 'r+' : 'w')) {
  if (flock($fp,LOCK_EX)) {
    $cnt = intval(fgets($fp));
    rewind($fp);
    fwrite($fp,++$cnt);
    flock($fp,LOCK_UN);
  }
  fclose($fp);
}
echo $cnt;
?>
 

vikm

Новичок
Спасибо всем, интересное обсуждение получилось,даже и предположить не мог,что тема получит такое бурное обсуждение.
 

Nicholas

Новичок
А обработка логов апача? Да и другие логи тоже...
Ага. Тогда накой нам нужен перл, си и иже с ними, если пыха отлично справляется?
Что-то нет у меня желания парсить на пхп логи апача.

> пользуйтесь file_get_contents, file_put_contents
Оно ещё и файлы лочит?
file_put_contents ($filename, $data, LOCK_EX);
А в чем проблема-то?

А зачем это:
>> file_exists($fp) ? 'r+' : 'w' (по сути, мы имеем лишний if)
и это:
>> rewind($fp); (файл же только открыт, указатель итак в самом начале).

В принципе, тему можно считать закрытой.
 

SiMM

Новичок
> А в чем проблема-то?
Проблема в том, что между file_get_contents и file_put_contents файл не залочен, соответственно при одновременном обращении к скрипту счётчик может недосчитаться запроса.

> по сути, мы имеем лишний if
По сути, файла cnt.txt могло и не быть в файловой системе.

> файл же только открыт, указатель итак в самом начале
А мужики-то и не знали, что fgets смещает указатель.
 
Сверху