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则是会清除之前的记录,只保留当前写入的内容
- $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;
- } //phpfensi.com
- RETURN_LONG(numbytes);
- }
- -->
什么时候用fwrite,file_put_contents ?
1,函数原型已经说明了它们处理的数据类型不一样
2,简单的文件处理,追求速度用fwrite
3,书写简单用file_put_contents – (啥类型的数据都能处理,magic阿。但是要理解类型判断机制,否则保存的数据可能不是你想要的)
Tags: fwrite file_put_contents
- 上一篇:PHP等额本息,等额本金计算方式例子
- 下一篇:PHP发送POST请求的常用方式
相关文章
- ·PHP flock文件锁详解介绍(2014-03-15)
推荐文章
热门文章
最新评论文章
- 写给考虑创业的年轻程序员(10)
- PHP新手上路(一)(7)
- 惹恼程序员的十件事(5)
- PHP邮件发送例子,已测试成功(5)
- 致初学者:PHP比ASP优秀的七个理由(4)
- PHP会被淘汰吗?(4)
- PHP新手上路(四)(4)
- 如何去学习PHP?(2)
- 简单入门级php分页代码(2)
- php中邮箱email 电话等格式的验证(2)