相同點:file_put_contents() 函數把一個字串寫入檔案中,與依次調用 fopen(),fwrite() 以及 fclose() 功能一樣。
不同點:在file_put_contents()函數中使用 FILE_APPEND 可避免刪除檔案中已有的內容,即實現多次寫入同一個檔案時的追加功能。
例如:
echo file_put_contents("test.txt","Hello World. Testing!",FILE_APPEND);
file_put_contents是以追加的形式將字串寫入到test.txt中,
fwrtie則是會清除之前的記錄,只保留當前寫入的內容
$file = fopen("test.txt","w");
echo fwrite($file,"Hello World. Testing!");
fclose($file);
file_put_contents代替fwrite優點多多
如下為file_put_contents的執行個體代碼:
<?php
$filename = 'file.txt';
$word = "你好!\r\nwebkaka"; //雙引號會換行 單引號不換行
file_put_contents($filename, $word);
?>
同樣的功能使用fwrite的執行個體代碼:
<?php
$filename = 'file.txt';
$word = "你好!\r\nwebkaka"; //雙引號會換行 單引號不換行
$fh = fopen($filename, "w"); //w從開頭寫入 a追加寫入
echo fwrite($fh, $word);
fclose($fh);
?>
從以上兩個例子看出,其實file_put_contents是fopen、fwrite、fclose三合一的簡化寫法,這對程式碼的最佳化是有好處的,一方面在代碼量上有所減少,另一方面不會出現fclose漏寫的不嚴密代碼,在調試、維護上方便很多。
上述例子裡,file_put_contents是從頭寫入,如果要追加寫入,怎麼辦呢?
在file_put_contents的文法裡,有個參數FILE_APPEND,這是追加寫入的聲明。執行個體代碼如下:
<?php
echo file_put_contents('file.txt', "This is another something.", FILE_APPEND);
?>
FILE_APPEND就是追加寫入的聲明。在追加寫入時,為了避免其他人同時操作,往往需要鎖定檔案,這時需要加多一個LOCK_EX的聲明,寫法如下:
<?php
echo file_put_contents('file.txt', "This is another something.", FILE_APPEND|LOCK_EX);
?>
注意,以上代碼中echo輸出到顯示器裡的是寫入檔案字串的長度。
常見問題:
Warning: fopen(file.txt) [function.fopen]: failed to open stream: Permission denied
當寫入檔案時,有時會遇到上述問題,這是因為檔案沒有寫入權限的原因。為了避免這個錯誤的出現,在寫入檔案時需要判斷下檔案是否可寫,這需要用到is_writable()這個函數。執行個體代碼如下:
<?php
$filename = 'file.txt';
if (is_writable($filename)) {
echo file_put_contents($filename, "This is another something.", FILE_APPEND);
} else {
echo "檔案 $filename 不可寫";
}
?>
fwrite簡單的把資料寫到handler裡面
file_put_contents可能需要處理contenxt,資料類型為mixed,需要更多處理
雖然看file_put_contents的函數說明:和依次調用 fopen(),fwrite() 以及 fclose() 功能一樣。
但是肯定有細微差別的,尤其是在重複寫入大量資料的時候,file_put_contents無疑會重複的fopen,fclose .而 fwrite則可以只一次fopen,fwrite即可
寫個簡單程式測試一下,一個250M檔案
<!--
<?php
$len = 1024*1024*25;
$data = str_repeat(“-”,$len);
$start = microtime(true);
$fp = fopen(“/tmp/b”,”w”);
fwrite($fp,$data,$len);
fclose($fp);
$end = microtime(true);
echo “elipsed time:”.($end-$start).”\n”;
$start = microtime(true);
file_put_contents(“/tmp/a”,$data);
$end = microtime(true);
echo “elipsed time:”.($end-$start).”\n”;
silver@silver-desktop:~/php$ php fwrite_VS_file_put_contents.php
elipsed time:6.0958020687103
elipsed time:9.6280250549316
silver@silver-desktop:~/php$ php fwrite_VS_file_put_contents.php
elipsed time:6.247565984726
elipsed time:9.0449070930481
…
-->
結論:多次執行結果類試,說明fopen,fwrite,fclose方式比直接file_put_contents要快一點!
那麼為什麼呢? 查看原始碼
我用的ubuntu12.04
直接sudo apt-get source php5
解壓:silver@silver-desktop:~/php/php5-5.3.3
尋找函數fwrite 函數:silver@silver-desktop:~/php/php5-5.3.3$ grep -rn “PHP_FUNCTION(fwrite)” .
./ext/standard/file.c:1233:PHPAPI PHP_FUNCTION(fwrite)
./ext/standard/file.h:43:PHPAPI PHP_FUNCTION(fwrite);
fwrite
找到對應源碼,該函數非常簡單:
<!--
PHP_FUNCTION(fwrite)
{
zval *arg1;
char *arg2;
int arg2len;
int ret;
int num_bytes;
long arg3 = 0;
char *buffer = NULL;
php_stream *stream;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, “rs|l”, &arg1, &arg2, &arg2len, &arg3) == FAILURE) {
RETURN_FALSE;
}
if (ZEND_NUM_ARGS() == 2) {
num_bytes = arg2len;
} else {
num_bytes = MAX(0, MIN((int)arg3, arg2len));
}
if (!num_bytes) {
RETURN_LONG(0);
}
PHP_STREAM_TO_ZVAL(stream, &arg1);
if (PG(magic_quotes_runtime)) {
buffer = estrndup(arg2, num_bytes);
php_stripslashes(buffer, &num_bytes TSRMLS_CC);
}
ret = php_stream_write(stream, buffer ? buffer : arg2, num_bytes);
if (buffer) {
efree(buffer);
}
RETURN_LONG(ret);
}
-->
file_put_contents
該函數的處理操作就多多了
<!--
PHP_FUNCTION(file_put_contents)
{
php_stream *stream;
char *filename;
int filename_len;
zval *data;
int numbytes = 0;
long flags = 0;
zval *zcontext = NULL;
php_stream_context *context = NULL;
php_stream *srcstream = NULL;
char mode[3] = “wb”;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, “sz/|lr!”, &filename, &filename_len, &data, &flags, &zcontext) == FAILURE) {
return;
}
if (Z_TYPE_P(data) == IS_RESOURCE) {
php_stream_from_zval(srcstream, &data);
}
context = php_stream_context_from_zval(zcontext, flags & PHP_FILE_NO_DEFAULT_CONTEXT);
if (flags & PHP_FILE_APPEND) {
mode[0] = ‘a’;
} else if (flags & LOCK_EX) {
/* check to make sure we are dealing with a regular file */
if (php_memnstr(filename, “://”, sizeof(“://”) – 1, filename + filename_len)) {
if (strncasecmp(filename, “file://”, sizeof(“file://”) – 1)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, “Exclusive locks may only be set for regular files”);
RETURN_FALSE;
}
}
mode[0] = ‘c’;
}
mode[2] = ‘\0′;
stream = php_stream_open_wrapper_ex(filename, mode, ((flags & PHP_FILE_USE_INCLUDE_PATH) ? USE_PATH : 0) | ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL, context);
if (stream == NULL) {
RETURN_FALSE;
}
if (flags & LOCK_EX && (!php_stream_supports_lock(stream) || php_stream_lock(stream, LOCK_EX))) {
php_stream_close(stream);
php_error_docref(NULL TSRMLS_CC, E_WARNING, “Exclusive locks are not supported for this stream”);
RETURN_FALSE;
}
if (mode[0] == ‘c’) {
php_stream_truncate_set_size(stream, 0);
}
switch (Z_TYPE_P(data)) {
case IS_RESOURCE: {
size_t len;
if (php_stream_copy_to_stream_ex(srcstream, stream, PHP_STREAM_COPY_ALL, &len) != SUCCESS) {
numbytes = -1;
} else {
numbytes = len;
}
break;
}
case IS_NULL:
case IS_LONG:
case IS_DOUBLE:
case IS_BOOL:
case IS_CONSTANT:
convert_to_string_ex(&data);
case IS_STRING:
if (Z_STRLEN_P(data)) {
numbytes = php_stream_write(stream, Z_STRVAL_P(data), Z_STRLEN_P(data));
if (numbytes != Z_STRLEN_P(data)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, “Only %d of %d bytes written, possibly out of free disk space”, numbytes, Z_STRLEN_P(data));
numbytes = -1;
}
}
break;
case IS_ARRAY:
if (zend_hash_num_elements(Z_ARRVAL_P(data))) {
int bytes_written;
zval **tmp;
HashPosition pos;
zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(data), &pos);
while (zend_hash_get_current_data_ex(Z_ARRVAL_P(data), (void **) &tmp, &pos) == SUCCESS) {
if (Z_TYPE_PP(tmp) != IS_STRING) {
SEPARATE_ZVAL(tmp);
convert_to_string(*tmp);
}
if (Z_STRLEN_PP(tmp)) {
numbytes += Z_STRLEN_PP(tmp);
bytes_written = php_stream_write(stream, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
if (bytes_written < 0 || bytes_written != Z_STRLEN_PP(tmp)) {
if (bytes_written < 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, “Failed to write %d bytes to %s”, Z_STRLEN_PP(tmp), filename);
} else {
php_error_docref(NULL TSRMLS_CC, E_WARNING, “Only %d of %d bytes written, possibly out of free disk space”, bytes_written, Z_STRLEN_PP(tmp));
}
numbytes = -1;
break;
}
}
zend_hash_move_forward_ex(Z_ARRVAL_P(data), &pos);
}
}
break;
case IS_OBJECT:
if (Z_OBJ_HT_P(data) != NULL) {
zval out;
//看看對像怎麼儲存的:)
if (zend_std_cast_object_tostring(data, &out, IS_STRING TSRMLS_CC) == SUCCESS) {
numbytes = php_stream_write(stream, Z_STRVAL(out), Z_STRLEN(out));
if (numbytes != Z_STRLEN(out)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, “Only %d of %d bytes written, possibly out of free disk space”, numbytes, Z_STRLEN(out));
numbytes = -1;
}
zval_dtor(&out);
break;
}
}
default:
numbytes = -1;
break;
}
php_stream_close(stream);
if (numbytes < 0) {
RETURN_FALSE;
}
RETURN_LONG(numbytes);
}
-->
什麼時候用fwrite,file_put_contents ?
1,函數原型已經說明了它們處理的資料類型不一樣
2,簡單的檔案處理,追求速度用fwrite
3,書寫簡單用file_put_contents – (啥類型的資料都能處理,magic阿。但是要理解類型判斷機制,否則儲存的資料可能不是你想要的)