老生常谈PHP 文件写入和读取(必看篇)


Posted in PHP onMay 22, 2017

文章提纲:

一.实现文件读取和写入的基本思路

二.使用fopen方法打开文件

三.文件读取和文件写入操作

四.使用fclose方法关闭文件

五.文件指针的移动

六.Windows和UNIX下的回车和换行

一.实现文件读取和写入的基本思路:

1.通过fopen方法打开文件:$fp =fopen(/*参数,参数*/),fp为Resource类型
2.进行文件读取或者文件写入操作(这里使用的函数以1中返回的$fp作为参数)
3. 调用fclose($fp)关闭关闭文件

二:使用fopen方法打开文件

fopen(文件路径[string],打开模式[string])

<1>fopen的第一个参数为文件路径
写文件路径的方式:1绝对路径,2相对路径

1绝对路径:

在windows下工作的小伙伴们应该很熟悉,windows下的路径分隔符是“\”而不是“/”,但我们在写入路径时不能以钦定的“\”为分隔符

老生常谈PHP 文件写入和读取(必看篇)

那如果我们以“\”分隔符写入路径会怎样呢?
<?php
   $fp = fopen("C:\wamp64\www\text.txt",'w');
?>
运行后报错,提示路径参数无效

老生常谈PHP 文件写入和读取(必看篇)

所以我们要把分隔符“\”换成“/”:
<?php
  $fp = fopen("C:/wamp64/www/text.txt",'w');
?>

运行时无报错,说明参数是有效的。

【注意】fopen函数不能理解“\”分隔符,如果你想要使用“\”,那么要使用转义,如写成:"C:\\wamp64\\www\\text.txt"这种写法也是可以的,函数也能理解,不会报错。但即使这样,也不推荐使用“\”,因为在OS(mac)下只能识别“/”不能识别“\”

本小节的结论:推荐坚持使用“/”作为分隔符

2.相对路径:

上一小节介绍的是绝对路径的写法,但这样却带来了另外一个问题:服务器的目录结构可能会有较大的改变,这时原来写的绝对路径就要全部重写了,比如在我的电脑上的目标文件路径是C:/wamp64/www/text.txt,如果我把www文件夹改名为penghuwan呢?原来写入的路径参数就失效了。所以我们引入了相对路径的写法:

<?php
  $DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT'];
  $fp = fopen("$DOCUMENT_ROOT/text.txt",'w');
?>

• $_SERVER是PHP的超级全局变量(在代码任何地方都可访问,类型是数组),通过$_SERVER['DOCUMENT_ROOT']可取到服务器的默认根目录

服务器的默认根目录可通过php.ini修改(这个可自行百度)

• $_SERVER['DOCUMENT_ROOT']在这里等同于C:/wamp64/www

本小节的结论:推荐使用相对路径

<2>fopen的第二个参数为打开模式

设置打开模式后,我们就相当于为接下来的读写操作设置了权限:

最基本的几个模式:

“r”:只能读取文件,不能写入文件(写入操作被忽略)
“w”:只能写入文件,不能读取文件(读取操作被忽略)
“a”:只追加文件,与“w”类似,区别是“w”删除原有的内容,“a”不删除原有内容,只追加内容

<?php
  $DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT'];
  $fp = fopen("$DOCUMENT_ROOT/text.txt",'w');
  fwrite($fp,'在写模式下写入');
  fclose($fp);
?>
在设置了写操作的权限后,就能正常地写入文件了
运行后打开C:/wamp64/www/text.txt:
老生常谈PHP 文件写入和读取(必看篇)
这次我们把权限设置为只读,并尝试写入文本:'在只读模式下写入'
<?php
  $DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT'];
  $fp = fopen("$DOCUMENT_ROOT/text.txt",'r');
  fwrite($fp,'在读模式下写入');
  fclose($fp);
?>
运行后打开C:/wamp64/www/text.txt,发现文件内容并没有改变,说明由于没有设置相应的权限,操作被忽略了
老生常谈PHP 文件写入和读取(必看篇)
关于打开模式的网络资料,我想大家最可能找到的是这张表:(图来自W3C)
老生常谈PHP 文件写入和读取(必看篇)

很全面,但我觉得这张表对新手有些不太友好,让人看后不知多云。 r是只读,w是只写(原来有的内容全删除),a是追加(不删除原有内容),这都好理解。

但r+,w+,和a+的区别和联系讲的实在太模糊了呀。 这里我就想详细地讲一下r+,w+,和a+三者的区别和联系:
首先r+,w+,和a+都是可读可写的,读取时的方式是一样的,关键在于写入方式的不同:
r+: 从文件[头部][覆盖]原有内容 ([不删除]原有内容);
a+:从文件[尾部][追加]内容 ([不删除]原有内容);
w+:[完全删除]原有内容,然后[再添加]新的内容
下面我依次演示上述的结论,首先我们没有写入的时候文本是”I am initialized value”(意为我是初始值)

老生常谈PHP 文件写入和读取(必看篇)

采用r+模式写入文本“r+ mode”
<?php
  $DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT'];
  $fp = fopen("$DOCUMENT_ROOT/text.txt",'r+');
  fwrite($fp,'r+ mode');
  fclose($fp);
?>
运行后再打开文本,发现“I am in”被“r+ mode”覆盖了:

老生常谈PHP 文件写入和读取(必看篇)

采用a+模式写入文本“a+ mode”
基于”I am initialized value”的初始文本我们运行以下代码:
<?php
  $DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT'];
  $fp = fopen("$DOCUMENT_ROOT/text.txt",'a+');
  fwrite($fp,'a+ mode');
  fclose($fp);
?>

老生常谈PHP 文件写入和读取(必看篇)

I am initialized value没有被删除和覆盖,而是在后面追加了a+ mode的这一段新文本
运行多次后:

老生常谈PHP 文件写入和读取(必看篇)

•采用w+模式写入文本“w+ mode”

基于”I am initialized value”的初始文本我们运行以下代码:
<?php
  $DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT'];
  $fp = fopen("$DOCUMENT_ROOT/text.txt",'w+');
  fwrite($fp,'w+ mode');
  fclose($fp);
?>
运行后,我们发现”I am initialized value”已经被删除了,然后才加上了“w+ mode”这段新文本
老生常谈PHP 文件写入和读取(必看篇)
【注意】r+,a+,w+还有一个区别是a+,w+在文件不存在时则创建文件,r+文件不存在时报错
【吐槽】:关于r+和w+,a+的区别,我找了网络上,包括W3C和各种博客文章以及那本“PHP圣经”上的各种资料,发现都是一笔带过去的,这也是我写这篇文章的原因
三.文件读取和文件写入操作
先说说几个比较重要的函数:
file_exists():判断文件是否存在,返回布尔值
filesize():判断一个文件大小,返回文件的字节数,为整型数字
unlink():删除一个文件
写入文件
fwrite(资源文件对象[string],写入方式[string]),资源文件对象即为fopen方法返回的参数,为Resource类型,写入方式可以是w(或者w+,a+,r+)
已经有上面的例子,这里就不放demo了
读取文件
这是我们要读取的文件内容:

老生常谈PHP 文件写入和读取(必看篇)

读取文件的方式有以下几种:
1.一次读取一个字节的数据 fgetc()
2.一次读取指定的字节数的数据 fread()
3.一次读取一行数据 fgets()/fgetcsv()
4.一次读完全部数据 fpassthru()/ file()
1. 一次读取一个字节 —— 通过fgetc()获取单个字节
<?php
   $DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT'];
   $fp = fopen("$DOCUMENT_ROOT/text.txt",'r');//打开文件
   if(file_exists("$DOCUMENT_ROOT/text.txt")){//当文件存在时,才读取内容
     while(!feof($fp)){//判断文件指针是否到达末尾
        $c = fgetc($fp);//每执行一次fgetc(),文件指针就向后移动一位
        echo $c;//输出获取到的字节
      }
    }
   fclose($fp);//关闭文件
?>
运行:
老生常谈PHP 文件写入和读取(必看篇)
【注意】:无论是按文本格式输入输出还是按二进制格式输出,fgetc()每次获取的是一个字节而不是一个字符
上面的例子中我们是逐个输出,现在让我们只做一次输出,看看结果怎样:
<?php
  $DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT'];
  $fp = fopen("$DOCUMENT_ROOT/text.txt",'r');
  echo fgetc($fp);//只做一次输出
  close($fp);
?>
运行结果如下,我们得到的不是汉字“我”,而是一个乱码,其实这个乱码就是一个字节
老生常谈PHP 文件写入和读取(必看篇)
<?php
   $DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT'];
   $fp = fopen("$DOCUMENT_ROOT/text.txt",'r');
   echo fgetc($fp);//连续做三次输出
   echo fgetc($fp);
   echo fgetc($fp);
   fclose($fp);
?>

2.一次读取多个字节 ——通过fread()方法:

<?php
  $DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT'];
  $fp = fopen("$DOCUMENT_ROOT/text.txt",'r');
  echo fread($fp, 3);//一次输出三个字节即一个汉字字符(UTF-8)
  fclose($fp);
?>
运行结果:

老生常谈PHP 文件写入和读取(必看篇)

改成:

echo fread($fp, 6);
运行结果如下,输出了6个字节也即两个汉字字符(UTF-8)
老生常谈PHP 文件写入和读取(必看篇)
3.一次读取一行——通过fgets()获取一行内容
<?php
    $DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT']
    $fp = fopen("$DOCUMENT_ROOT/text.txt",'r');//打开文件
    if(file_exists("$DOCUMENT_ROOT/text.txt")){//当文件存在时,才读取内容
     while(!feof($fp)){//判断文件指针是否到达末尾
       $line = fgets($fp);//返回一行文本,并将文件指针移动到下一行头部
       echo $line."<br/>";//输出获取到的一行文本
     }
    }
    fclose($fp);//关闭文件
?>

老生常谈PHP 文件写入和读取(必看篇)

fgets()其实还有第二个参数,这个参数规定了每一行能读取的最大字节数(注意是字节数不是字符数):
【注意】在UTF-8编码下汉字3字节,字母1字节
下面我修改上面的一行,代码,使获取的每一行最大字符数为3(也即字节数为9)
$line = fgets($fp,10);
Demo:
老生常谈PHP 文件写入和读取(必看篇)
【注意】:这里我fgets()里第二个参数为10,为什么是10呢?因为
1.这里的长度是按字节数算的
2.一个汉字占3个字节。fgets($fp,10)代表一次最多读取10 - 1 = 9字节
4.一次读完全部文件 ——fpassthru() or file()?
fpassthru()将读取文件并直接输出(无处理过程)
<?php
   $DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT'];
   $fp = fopen("$DOCUMENT_ROOT/text.txt",'r');
   fpassthru($fp);
   fclose($fp);
?>
运行结果:
老生常谈PHP 文件写入和读取(必看篇)
【注意】这里需要注意一点的是,我们并没有从fpassthru($fp)获取到返回值然后echo到页面上去,也就是说这个方法是会强制输出获取的内容的,而并不是像之前例子的方法那样返回文本,允许我们保存到变量中才将其输出
将读取到的全部内容保存到一个数组中,每个数组元素为一行的内容——fille()
<?php
  $DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT'];
  $file_array = file("$DOCUMENT_ROOT/text.txt");//取到文件数组
  foreach ($file_array as $value) {//输出数组元素
    echo $value."<br/>";
  }
?>

老生常谈PHP 文件写入和读取(必看篇)

【注意】:这里我们并不需要写fopen和fclose哦!也就是说file()方法已经帮我们做了这一步了
四.使用fclose方法关闭文件
fclose()将返回一个布尔值,成功关闭为true,关闭失败为false(失败的情况很少出现,可不考虑)
是否打开文件后一定要关闭?
1即使不手写fclose,在PHP脚本执行结束后,也会自动关闭文件的
2但在一个长时间执行的脚本中,如果不写关闭文件的fclose(),在文件加锁的情况下会造成操作的阻塞,所以,写fclose是个好习惯
五.文件指针的移动
我们上面调用的读取文件的函数,其实都是基于文件指针去打印的,每读取一段字节内容,文件指针就向后移动一段字节长度,直到被读取的文件最大字节长度为止
<?php
     $DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT'];
     function print_file_pointer($fp){//定义一个打印文件指针位置的函数
       echo " <br/>//此时文件指针的位置:";
       echo ftell($fp)."<br/>";
     }
     $fp = fopen("$DOCUMENT_ROOT/text.txt",'r');
     echo fgetc($fp);//通过fgetc连续输出三个字节
     echo fgetc($fp);
     echo fgetc($fp);
     print_file_pointer($fp);//打印此刻文件指针的位置
     
     echo fread($fp,6);//通过fread一次输出6字节
     print_file_pointer($fp);//打印此刻文件指针的位置
     
     echo fgets($fp); //通过fgets输出一整行
     print_file_pointer($fp);//打印此刻文件指针的位置
     
     fpassthru($fp); //一次性输出全部内容
     print_file_pointer($fp);//打印此刻文件指针的位置
     
     fseek($fp, 33);//使文件指针移动到33字节位置
     print_file_pointer($fp);//打印此刻文件指针的位置
     
     rewind($fp);//使文件指针移动到0字节位置(初始位置)
     print_file_pointer($fp);//打印此刻文件指针的位置
$fclose($fp);
?>
Demo:
老生常谈PHP 文件写入和读取(必看篇)
所以我们需要正确理解fgets(),fpassthru()这些函数的作用:
fgets():从当前文件指针的位置到本行结束的数据,而不是一定输出一整行
fpassthru():从当前文件指针的位置到全部内容结束的数据,而不是一定输出所有的数据
但在这里你可能会有疑问:为什么输出“湖湾”后的指针位置会是17而不是15呢?按理说输出“我叫彭湖湾”这5个汉字一共占3*5 = 15个字节,多出来的17 - 15 =2字节是什么呢?
多出来的两个字节是windows下的回车换行符\n\r
\n是换行,占一字节,\r是回车,占一字节,在六中我将会介绍
六.Windows和UNIX下的回车和换行
<?php
   $DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT'];
   $fp = fopen("$DOCUMENT_ROOT/text.txt",'r');
   while(!feof($fp)){
    echo fgets($fp);
    echo ftell($fp);
   }
   fclose($fp);
?>
我们在windows下敲下回车键的时候,相当于键入了\n\r,所以“我叫彭湖湾”的15字节+“\n\r”的2字节 = 17字节
老生常谈PHP 文件写入和读取(必看篇)
在mac下不一样的是:敲下回车键的时候,相当于只键入了\n,所以“我叫彭湖湾”的15字节+“\n”的1字节 = 16字节
老生常谈PHP 文件写入和读取(必看篇)

以上这篇老生常谈PHP 文件写入和读取(必看篇)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
多重?l件?合查?(一)
Oct 09 PHP
完美解决dedecms中的[html][/html]和[code][/code]问题
Mar 20 PHP
php一些公用函数的集合
Mar 27 PHP
php数据结构与算法(PHP描述) 快速排序 quick sort
Jun 21 PHP
PHP中全局变量global和$GLOBALS[]的区别分析
Aug 06 PHP
APACHE的AcceptPathInfo指令使用介绍
Jan 18 PHP
php禁止某ip或ip地址段访问的方法
Feb 25 PHP
PHP中的魔术方法总结和使用实例
May 11 PHP
PHP Reflection API详解
May 12 PHP
PHP实现基于栈的后缀表达式求值功能
Nov 10 PHP
php7性能提升的原因详解
Oct 13 PHP
Laravel 登录后清空COOKIE的操作方法
Oct 14 PHP
PHP中trait使用方法详细介绍
May 21 #PHP
php写app接口并返回json数据的实例(分享)
May 20 #PHP
PHP实现json_decode不转义中文的方法
May 20 #PHP
Yii框架参数化查询中IN查询只能查询一个的解决方法
May 20 #PHP
Yii框架使用魔术方法实现跨文件调用功能示例
May 20 #PHP
Yii框架实现的验证码、登录及退出功能示例
May 20 #PHP
利用Laravel事件系统如何实现登录日志的记录详解
May 20 #PHP
You might like
IIS+PHP+MySQL+Zend配置 (视频教程)
2006/12/13 PHP
php jquery 实现新闻标签分类与无刷新分页
2009/12/18 PHP
php中去除所有js,html,css代码
2010/10/12 PHP
分享一段php获取linux服务器状态的代码
2014/05/27 PHP
php+mysql大量用户登录解决方案分析
2014/12/29 PHP
php实现简易聊天室应用代码
2015/09/23 PHP
使用PHP实现微信摇一摇周边红包
2016/01/04 PHP
php使用CURL模拟GET与POST向微信接口提交及获取数据的方法
2016/09/23 PHP
Js 时间函数getYear()的使用问题探讨
2013/04/01 Javascript
JQuery AJAX 中文乱码问题解决
2013/06/05 Javascript
js正则表达式中test,exec,match方法的区别说明
2014/01/29 Javascript
使用jspdf生成pdf报表
2015/07/03 Javascript
jQuery中(function($){})(jQuery)详解
2015/07/15 Javascript
jquery插件tytabs.jquery.min.js实现渐变TAB选项卡效果
2015/08/25 Javascript
jQuery中slidedown与slideup方法用法示例
2016/09/16 Javascript
详解从Node.js的child_process模块来学习父子进程之间的通信
2017/03/27 Javascript
一份超级详细的Vue-cli3.0使用教程【推荐】
2018/11/15 Javascript
JavaScript数值类型知识汇总
2019/11/17 Javascript
[58:37]Serenity vs Fnatic 2018国际邀请赛淘汰赛BO1 8.21
2018/08/22 DOTA
pycharm+django创建一个搜索网页实例代码
2018/01/24 Python
python使用turtle库绘制树
2018/06/25 Python
Python嵌套式数据结构实例浅析
2019/03/05 Python
Python实现时间序列可视化的方法
2019/08/06 Python
Python虚拟环境venv用法详解
2020/05/25 Python
Python过滤掉numpy.array中非nan数据实例
2020/06/08 Python
python的链表基础知识点
2020/09/13 Python
德国机车企业:FC-Moto
2017/10/27 全球购物
卡拉威高尔夫官方网站:Callaway Golf
2020/09/16 全球购物
Overload和Override的区别
2012/09/02 面试题
给护士表扬信
2014/01/19 职场文书
企业出纳岗位职责
2014/03/12 职场文书
开工仪式主持词
2014/03/20 职场文书
小学综治宣传月活动总结
2014/07/02 职场文书
法定代表人授权委托书范本
2014/10/07 职场文书
社区节水倡议书
2015/04/29 职场文书
党员转正申请报告
2015/05/15 职场文书