当前位置:首页 > PHP教程 > php应用 > 列表

PHP中fwrite与file_put_contents的区别

发布:smiling 来源: PHP粉丝网  添加日期:2018-09-15 22:54:41 浏览: 评论:0 

相同点: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则是会清除之前的记录,只保留当前写入的内容

  1. $file = fopen("test.txt","w"); 
  2. echo fwrite($file,"Hello World. Testing!"); 
  3. fclose($file); 

file_put_contents代替fwrite优点多多

如下为file_put_contents的实例代码:

  1. <?php 
  2. $filename = 'file.txt'
  3. $word = "你好!\r\nwebkaka";  //双引号会换行 单引号不换行 
  4. file_put_contents($filename$word); 
  5. ?> 

同样的功能使用fwrite的实例代码:

  1. <?php 
  2. $filename = 'file.txt'
  3. $word = "你好!\r\nwebkaka";  //双引号会换行  单引号不换行 
  4. $fh = fopen($filename"w"); //w从开头写入 a追加写入 
  5. echo fwrite($fh$word); 
  6. fclose($fh); 
  7. ?> 

从以上两个例子看出,其实file_put_contents是fopen、fwrite、fclose三合一的简化写法,这对程序代码的优化是有好处的,一方面在代码量上有所减少,另一方面不会出现fclose漏写的不严密代码,在调试、维护上方便很多。

上述例子里,file_put_contents是从头写入,如果要追加写入,怎么办呢?

在file_put_contents的语法里,有个参数FILE_APPEND,这是追加写入的声明。实例代码如下:

  1. <?php 
  2. echo file_put_contents('file.txt'"This is another something.", FILE_APPEND); 
  3. ?> 

FILE_APPEND就是追加写入的声明。在追加写入时,为了避免其他人同时操作,往往需要锁定文件,这时需要加多一个LOCK_EX的声明,写法如下:

  1. <?php 
  2. echo file_put_contents('file.txt'"This is another something.", FILE_APPEND|LOCK_EX); 
  3. ?> 

注意,以上代码中echo输出到显示器里的是写入文件字符串的长度。

常见问题:

Warning: fopen(file.txt) [function.fopen]: failed to open stream: Permission denied

当写入文件时,有时会遇到上述问题,这是因为文件没有写权限的原因。为了避免这个错误的出现,在写入文件时需要判断下文件是否可写,这需要用到is_writable()这个函数。实例代码如下:

  1. <?php 
  2. $filename = 'file.txt'
  3. if (is_writable($filename)) { 
  4. echo file_put_contents($filename"This is another something.", FILE_APPEND); 
  5. else { 
  6.     echo "文件 $filename 不可写"
  7. ?> 

fwrite简单的把数据写到handler里面。

file_put_contents可能需要处理contenxt,数据类型为mixed,需要更多处理,虽然看file_put_contents的函数说明:和依次调用 fopen(),fwrite() 以及 fclose() 功能一样。

但是肯定有细微差别的,尤其是在重复写入大量数据的时候,file_put_contents无疑会重复的fopen,fclose .而 fwrite则可以只一次fopen,fwrite即可。

写个简单程序测试一下,一个250M文件

  1. <!-- 
  2. <?php 
  3. $len = 1024*1024*25; 
  4. $data = str_repeat(“-”,$len); 
  5. $start = microtime(true); 
  6. $fp = fopen(“/tmp/b”,”w”); 
  7. fwrite($fp,$data,$len); 
  8. fclose($fp); 
  9. $end = microtime(true); 
  10. echo “elipsed time:”.($end-$start).”\n”; 
  11. $start = microtime(true); 
  12. file_put_contents(“/tmp/a”,$data); 
  13. $end = microtime(true); 
  14. echo “elipsed time:”.($end-$start).”\n”; 
  15. silver@silver-desktop:~/php$ php fwrite_VS_file_put_contents.php 
  16. elipsed time:6.0958020687103 
  17. elipsed time:9.6280250549316 
  18. silver@silver-desktop:~/php$ php fwrite_VS_file_put_contents.php 
  19. elipsed time:6.247565984726 
  20. elipsed time:9.0449070930481 
  21. … 
  22. --> 

结论:多次执行结果类试,说明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

找到对应源码,该函数非常简单:

  1. <!-- 
  2. PHP_FUNCTION(fwrite) 
  3. zval *arg1; 
  4. char *arg2; 
  5. int arg2len; 
  6. int ret; 
  7. int num_bytes; 
  8. long arg3 = 0; 
  9. char *buffer = NULL; 
  10. php_stream *stream; 
  11. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, “rs|l”, &arg1, &arg2, &arg2len, &arg3) == FAILURE) { 
  12. RETURN_FALSE; 
  13. if (ZEND_NUM_ARGS() == 2) { 
  14. num_bytes = arg2len; 
  15. else { 
  16. num_bytes = MAX(0, MIN((int)arg3, arg2len)); 
  17. if (!num_bytes) { 
  18. RETURN_LONG(0); 
  19. PHP_STREAM_TO_ZVAL(stream, &arg1); 
  20. if (PG(magic_quotes_runtime)) { 
  21. buffer = estrndup(arg2, num_bytes); 
  22. php_stripslashes(buffer, &num_bytes TSRMLS_CC); 
  23. ret = php_stream_write(stream, buffer ? buffer : arg2, num_bytes); 
  24. if (buffer) { 
  25. efree(buffer); 
  26. RETURN_LONG(ret); 
  27. --> 

file_put_contents

该函数的处理操作就多多了

  1. <!-- 
  2. PHP_FUNCTION(file_put_contents
  3. php_stream *stream; 
  4. char *filename; 
  5. int filename_len; 
  6. zval *data; 
  7. int numbytes = 0; 
  8. long flags = 0; 
  9. zval *zcontext = NULL; 
  10. php_stream_context *context = NULL; 
  11. php_stream *srcstream = NULL; 
  12. char mode[3] = “wb”; 
  13. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, “sz/|lr!”, &filename, &filename_len, &data, &flags, &zcontext) == FAILURE) { 
  14. return
  15. if (Z_TYPE_P(data) == IS_RESOURCE) { 
  16. php_stream_from_zval(srcstream, &data); 
  17. context = php_stream_context_from_zval(zcontext, flags & PHP_FILE_NO_DEFAULT_CONTEXT); 
  18. if (flags & PHP_FILE_APPEND) { 
  19. mode[0] = ‘a’; 
  20. else if (flags & LOCK_EX) { 
  21. /* check to make sure we are dealing with a regular file */ 
  22. if (php_memnstr(filename, “://”, sizeof(“://”) – 1, filename + filename_len)) { 
  23. if (strncasecmp(filename, “file://”, sizeof(“file://”) – 1)) { 
  24. php_error_docref(NULL TSRMLS_CC, E_WARNING, “Exclusive locks may only be set for regular files”); 
  25. RETURN_FALSE; 
  26. mode[0] = ‘c’; 
  27. mode[2] = ‘\0′; 
  28. stream = php_stream_open_wrapper_ex(filename, mode, ((flags & PHP_FILE_USE_INCLUDE_PATH) ? USE_PATH : 0) | ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL, context); 
  29. if (stream == NULL) { 
  30. RETURN_FALSE; 
  31. if (flags & LOCK_EX && (!php_stream_supports_lock(stream) || php_stream_lock(stream, LOCK_EX))) { 
  32. php_stream_close(stream); 
  33. php_error_docref(NULL TSRMLS_CC, E_WARNING, “Exclusive locks are not supported for this stream”); 
  34. RETURN_FALSE; 
  35. if (mode[0] == ‘c’) { 
  36. php_stream_truncate_set_size(stream, 0); 
  37. switch (Z_TYPE_P(data)) { 
  38. case IS_RESOURCE: { 
  39. size_t len; 
  40. if (php_stream_copy_to_stream_ex(srcstream, stream, PHP_STREAM_COPY_ALL, &len) != SUCCESS) { 
  41. numbytes = -1; 
  42. else { 
  43. numbytes = len; 
  44. break
  45. case IS_NULL
  46. case IS_LONG
  47. case IS_DOUBLE
  48. case IS_BOOL
  49. case IS_CONSTANT: 
  50. convert_to_string_ex(&data); 
  51. case IS_STRING
  52. if (Z_STRLEN_P(data)) { 
  53. numbytes = php_stream_write(stream, Z_STRVAL_P(data), Z_STRLEN_P(data)); 
  54. if (numbytes != Z_STRLEN_P(data)) { 
  55. 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)); 
  56. numbytes = -1; 
  57. break
  58. case IS_ARRAY
  59. if (zend_hash_num_elements(Z_ARRVAL_P(data))) { 
  60. int bytes_written; 
  61. zval **tmp; 
  62. HashPosition pos; 
  63. zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(data), &pos); 
  64. while (zend_hash_get_current_data_ex(Z_ARRVAL_P(data), (void **) &tmp, &pos) == SUCCESS) { 
  65. if (Z_TYPE_PP(tmp) != IS_STRING) { 
  66. SEPARATE_ZVAL(tmp); 
  67. convert_to_string(*tmp); 
  68. if (Z_STRLEN_PP(tmp)) { 
  69. numbytes += Z_STRLEN_PP(tmp); 
  70. bytes_written = php_stream_write(stream, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); 
  71. if (bytes_written < 0 || bytes_written != Z_STRLEN_PP(tmp)) { 
  72. if (bytes_written < 0) { 
  73. php_error_docref(NULL TSRMLS_CC, E_WARNING, “Failed to write %d bytes to %s”, Z_STRLEN_PP(tmp), filename); 
  74. else { 
  75. 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)); 
  76. numbytes = -1; 
  77. break
  78. zend_hash_move_forward_ex(Z_ARRVAL_P(data), &pos); 
  79. break
  80. case IS_OBJECT
  81. if (Z_OBJ_HT_P(data) != NULL) { 
  82. zval out; 
  83. //看看对像怎么保存的:) 
  84. if (zend_std_cast_object_tostring(data, &out, IS_STRING TSRMLS_CC) == SUCCESS) { 
  85. numbytes = php_stream_write(stream, Z_STRVAL(out), Z_STRLEN(out)); 
  86. if (numbytes != Z_STRLEN(out)) { 
  87. php_error_docref(NULL TSRMLS_CC, E_WARNING, “Only %d of %d bytes written, possibly out of free disk space”, numbytes, Z_STRLEN(out)); 
  88. numbytes = -1; 
  89. zval_dtor(&out); 
  90. break
  91. default
  92. numbytes = -1; 
  93. break
  94. php_stream_close(stream); 
  95. if (numbytes < 0) { 
  96. RETURN_FALSE; 
  97. //phpfensi.com 
  98. RETURN_LONG(numbytes); 
  99. --> 

什么时候用fwrite,file_put_contents ?

1,函数原型已经说明了它们处理的数据类型不一样

2,简单的文件处理,追求速度用fwrite

3,书写简单用file_put_contents – (啥类型的数据都能处理,magic阿。但是要理解类型判断机制,否则保存的数据可能不是你想要的)


Tags: fwrite file_put_contents

分享到:

相关文章