老生常谈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 相关文章推荐
使用Xdebug调试和优化PHP程序之[1]
Apr 17 PHP
PHP 错误之引号中使用变量
May 04 PHP
php disk_free_space 返回目录可用空间
May 10 PHP
php数据库密码的找回的步骤
Jan 12 PHP
对淘宝URL中ID提取的PHP代码
Sep 01 PHP
ThinkPHP视图查询详解
Jun 30 PHP
php自定义urlencode,urldecode函数实例
Mar 24 PHP
分享10段PHP常用代码
Nov 11 PHP
在openSUSE42.1下编译安装PHP7 的方法
Dec 24 PHP
php微信开发之自定义菜单实现
Nov 18 PHP
PHP+Ajax实现的无刷新分页功能详解【附demo源码下载】
Jul 03 PHP
php 使用expat方式解析xml文件操作示例
Nov 26 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
【COS正片】蕾姆睡衣cos,纯洁可爱被治愈了 cn名濑弥七
2020/03/02 日漫
JAVA/JSP学习系列之七
2006/10/09 PHP
一个基于PDO的数据库操作类
2011/03/24 PHP
linux下使用ThinkPHP需要注意大小写导致的问题
2011/08/02 PHP
php include和require的区别深入解析
2013/06/17 PHP
神盾加密解密教程(二)PHP 神盾解密
2014/06/08 PHP
PHP SPL标准库之文件操作(SplFileInfo和SplFileObject)实例
2015/05/11 PHP
php单例模式的简单实现方法
2016/06/10 PHP
基于laravel-admin 后台 列表标签背景的使用方法
2019/10/03 PHP
接收键盘指令的脚本
2006/06/26 Javascript
在Javascript里访问SharePoint列表数据的实现方法
2011/05/22 Javascript
输入自动提示搜索提示功能的javascript:sugggestion.js
2013/09/02 Javascript
JS小游戏之象棋暗棋源码详解
2014/09/25 Javascript
利用JavaScript脚本实现滚屏效果的方法
2015/07/07 Javascript
Javascript中的arguments对象
2016/06/20 Javascript
用v-html解决Vue.js渲染中html标签不被解析的问题
2016/12/14 Javascript
JS实现仿UC浏览器前进后退效果的实例代码
2017/07/17 Javascript
Vue实现web分页组件详解
2017/11/28 Javascript
前端性能优化建议
2020/09/17 Javascript
python字典多条件排序方法实例
2014/06/30 Python
基于Python的身份证号码自动生成程序
2014/08/15 Python
Selenium定位元素操作示例
2018/08/10 Python
基于numpy中数组元素的切片复制方法
2018/11/15 Python
在PyCharm中遇到pip安装 失败问题及解决方案(pip失效时的解决方案)
2020/03/10 Python
Python实现疫情通定时自动填写功能(附代码)
2020/05/27 Python
Python 如何查找特定类型文件
2020/08/17 Python
阿玛尼化妆品美国官网:Giorgio Armani Beauty
2017/02/02 全球购物
Nike瑞典官方网站:Nike.com (SE)
2018/11/26 全球购物
西班牙家用电器和电子产品购物网站:Mi Electro
2019/02/25 全球购物
理工大学毕业生自荐信
2013/11/01 职场文书
土木工程专业个人求职信
2013/12/30 职场文书
2014年“向国旗敬礼”网上签名寄语活动方案
2014/09/27 职场文书
2014年党员教师自我剖析材料
2014/09/30 职场文书
党的群众路线对照检查材料思想汇报(学校)
2014/10/04 职场文书
2015年学校安全工作总结
2015/04/22 职场文书
MySQL数据库如何使用Shell进行连接
2022/04/12 MySQL