美文网首页php
PHP学习笔记之文件系统处理

PHP学习笔记之文件系统处理

作者: akon2016 | 来源:发表于2017-01-12 20:44 被阅读24次

    导语####

    任何类型的变量,都是在程序运行期间才将数据加载到内存中的,并不能持久保存。如果需要将数据长久保存起来,以便后期程序再次运行时还可以使用,存储的基本方法通常有两种:将需要持久化的数据保存到普通文件或数据库中。而对文件的处理因为比较繁琐,所以并不是用来持久储存数据的首选,但在任何计算机设备中,文件都是必需的对象,尤其是在Web编程中,文件的操作是非常有用的,我们可以在客户端通过访问PHP脚本程序,动态地在Web服务器上生成目录,创建、编辑、修改文件,像开发采集程序、网页静态化、文件上传及下载等操作都离不开文件处理。

    一、文件####

    1、文件类型

    PHP是以UNIX的文件系统为模型的,因此在Windows系统中我们只能获得"file"、"dir"、"unknown"三种文件类型。而在UNIX系统中,我们可以获得"block"、"char"、"dir"、"fifo"、"file"、"link"或"unknown"7种文件类型

    fileType: 获取文件的类型,该函数接受一个文件名为参数,如果文件不存在返回false。

    2、文件属性

    函数名 作用 参数 返回值
    file_exists() 检查文件是否存在 文件名 文件存在返回TRUE
    filesize() 取得文件大小 文件名 返回文件大小的字节数
    is_readable() 判断文件名是否可读 文件名 存在且可读返回TRUE
    is_writable() 判断文件名是否可写 文件名 存在且可读写返回TRUE
    is_executable() 判断文件名是否可执行 文件名 存在且可执行返回TRUE
    filectime() 获取文件的创建时间 文件名 返回UNIX时间戳格式
    filemtime() 获取文件的修改时间 文件名 返回UNIX时间戳格式
    fileatime() 获取文件的访问时间 文件名 返回UNIX时间戳格式
    stat() 获取文件的大部分属性 文件名 返回文件有用信息的数组

    代码示例:

    /*声明一个函数,通过传入一个文件名获取文件的部分属性*/
    function getFilePro($fileName){
      //如果文件或目录不存在,则直接退出目录
      if(!file_exists($fileName)){
          echo "目标文件不存在<br/>";
          return;
      }
      
      //判断是否是一个普通文件
      if(is_file($fileName)){
          echo $fileName . "是一个文件<br/>";
      }
    
      //判断是否是一个目录
      if(is_dir($fileName)){
          echo $fileName . "是一个目录<br/>";
      }
    
      //用定义的函数输出文件类型
      echo "文件类型:" . getFileType($fileName) . "<br/>";
      //用定义的函数输出文件大小
      echo "文件大小:" . getFileSize(fileSize($fileName)) . "<br/>";
      
      //判断文件是否可读
      if(is_readable($fileName)) echo "文件可读<br/>";
      //判断文件是否可写
      if(is_writable($fileName)) echo "文件可写<br/>";
      //判断文件是否可以执行
      if(is_executable($fileName)) echo "文件可执行<br/>";
    
      echo "文件创建时间:" . date("Y年m月j日",filectime($fileName)) . "<br/>;
      echo "文件最后修改时间:" . date("Y年m月j日",filemtime($fileName)) . "<br/>";
      echo "文件最后打开时间:" . date("Y年m月j日",fileatime($fileName)) . "<br/>";
      /**声明一个函数,用来返回文件的类型**/
      function getFileType($fileName){
        switch(fileType($fileName)){
            case 'file' : $type = "普通文件"; break;
            case 'dir'  : $type = "目录文件"; break;
            case 'block' : $type = "块设备文件"; break;
            case 'char'   : $type = "字符设备文件"; break;
            case 'fifo'     : $type = "命名管道文件"; break;
            case 'link'     : $type = "符号链接"; break;
            case 'unknown : $type = "未知文件"; break;
            default : $type = "没有检测到文件类型"; break;
        }
        return $type;
      }
    }
    
      /**声明一个函数,用来返回文件的大小**/
      function getFileSize($bytes){
        if($bytes >= pow(2,40)){
            $res = round($bytes / pow(1024,4),2);
            $suffix = "TB";
        }else if($bytes >= pow(2,30)){
            $res = round($bytes / pow(1024,3),2);
            $suffix = "GB";
        }else if($bytes >= pow(2,20)){
            $res = round($bytes / pow(1024,2),2);
            $suffix = "MB";
        }else if($bytes >= pow(2,10)){
            $res = round($bytes / pow(1024,1),2);
            $suffix = "KB";
        }else{
            $res = $bytes;
            $suffix = "Bytes";
        }
        return $res . " " . $suffix;
      }
    

    二、目录####

    1、解析目录路径

    • 绝对路径:从根目录开始一级一级地进入各个子目录,最后指定改文件名或目录名。
    • 相对路径:从当前目录进入某目录,最后指定改文件名或目录名。

      在系统的每个目录下都有两个特殊的目录“.”和“..”,分别指示当前目录和当前目录的父目录
      在UNIX系统和Windows系统中,目录分隔符是不同的,在UNIX系统中必须使用正斜线“/”作为路径分隔符,而在Windows系统中默认使用反斜线“\”作为路径分隔符,在程序中表示时还要将“\”转义,但也接受正斜线“/”的写法。建议都是用“/”作为文件的路径分隔符。另外,也可以使用PHP内置常量DIRECTORY_SEPARATOR,其值为当前操作系统的默认文件路径分隔符。
    下面为几个常用的函数:
    basename():返回路径中的文件名部分

    dirname():返回去掉文件名后的目录名

    pathinfo():返回一个关联数组,包含路径中的目录名、基本名、扩展名

    2、遍历目录
    opendir():打开指定目录,接受一个目录的路径及目录名作为参数,函数返回值为可供其他目录函数使用的目录句柄(资源类型)。如果该目录不存在或没有访问权限,则返回false。
    readdir():用于读取指定目录,接受已经用opendir()打开的卡操作目录句柄作为参数,函数返回当前目录指针位置的一个文件名,并将目录指针向后移动一位。当指针位于目录的结尾使,因为没有文件存在则返回false。
    closedir():关闭指定目录,接受已经用opendir()打开的可操作目录句柄作为参数,函数无返回值,运行后将关闭打开的目录。
    rewinddir():倒回目录句柄,接受已经用opendir()打开的可操作目录句柄作为参数,将目录指针重置目录到开始处,即倒回目录的开头。
    代码示例:

    /****完整的遍历目录下所有的指定文件类型函数****/
    function traverse($path = '.') {
        $current_dir = opendir($path);    //opendir()返回一个目录句柄,失败返回false
        while(($file = readdir($current_dir)) !== false) {    //readdir()返回打开目录句柄中的一个条目
            //$sub_dir = $path . DIRECTORY_SEPARATOR . $file;    //构建子目录路径  DIRECTORY_SEPARATOR 代表反斜线 \
            $sub_dir = $path . '/' . $file;
            if($file == '.' || $file == '..') {
                continue;
            } else if(is_dir($sub_dir)) {    //如果是目录,进行递归
                echo 'Directory ' . $file . ':<br>';
                traverse($sub_dir);
            } else {    //如果是文件,直接输出
                echo 'File in Directory ' . $path . ': ' . $file . '<br>';
            }
        }
    }
    traverse('../../');
    

    3、统计目录大小
    代码示例:

    /**自定义一个函数,用于统计传入参数的目录大小**/
    function getDirSize($dirName){
      $dir_size = 0;                                               //用来累计各个文件大小
      if($dir_handle = opendir($dirName)){
          while(($file = readdir($dir_handle)) !== false){
              if($file == '.' || $file == '..') continue;          //排除两个特殊目录
              $subFile = $dirName . DIRECTORY_SEPARATOR . $file;   //将目录下的子文件和当前目录相连
              if(is_dir($subFile)){
                  $dir_size += getDirSize($subFile);               //递归地调用自身函数,求子目录的大小
              }else{
                  $dir_size += filesize($subFile);
              }
          }
          closedir($dir_handle);
      }
      return $dir_size;
    }
    

    4、建立和删除目录
    mkdir():创建目录【以最高权限创建目录 mkdir(目录名,0777,true)】
    rmdir():删除目录,只能删除一个空目录并且目录必须存在
    自定义递归函数删除目录的示例代码:

    function delDir($dir){
        if(file_exists($dir)){                                      //如果不存在rmdir(0函数会出错
            if($dir_handle = @opendir($dir)){                       //打开目录并判断是否成功
                while(($file = readdir($dir_handle)) !== false){    //循环便利目录
                    if($file == '.' || $file == '..') continue;     //一定要排除两个特殊的目录
                    $subFile = $dir . DIRECTORY_SEPARATOR . $file;  //将目录下的文件和当前目录相连
                    if(is_dir($subFile)){                           //如果是目录则条件成立
                        delDir($subFile);                           //递归
                    }else{
                        unlink($subFile);                           //删除文件
                    }
                }
                closedir($dir_handle);
                rmdir($dir);                                        //删除空目录
            }
        }
    }
    

    5、复制目录

    function copyDir($dirSrc,$dirTo){
        if(is_file($dirTo)){
            echo "目标不是目录不能创建";
            return;
        }
        if(!file_exists($dirTo)){
            mkdir($dirTo,0777,true);
        }
    
        if($dir_handle = @opendir($dirSrc)){
            while(($file = readdir($dir_handle)) !== false){
                if($file == '.' || $file == '..') continue;
                $subSrcFile = $dirSrc .DIRECTORY_SEPARATOR . $file;
                $subToFile = $dirTo . DIRECTORY_SEPARATOR . $file;
                if(is_dir($subSrcFile)){
                    copyDir($subSrcFile,$subToFile);
                }
                if(is_file($subSrcFile)){
                    copy($subSrcFile,$subToFile);
                }
            }
            closedir($dir_handle);
        }
    }
    copyDir('vendor','photos/vendor');
    

    三、文件的基本操作####

    1、文件的打开与关闭

    • fopen():打开文件,建立与文件资源的连接,并使文件指针指向文件。
    • fclose():关闭文件,即断开文件指针与文件之间的联系。

    在fopen()中第二个参数可以使用的文件模式

    模式 描述
    r 只读方式打开文件,从文件开头开始读
    r+ 读写方式打开文件,从文件开头开始读写
    w 只写方式打开文件,从文件开头开始写。如果文件已经存在,将文件指针指向文件头并将文件大小截为零,即删除所有文件已有的内容。如果文件不存在,函数将创建这个文件
    w+ 读写方式打开文件,从文件头开始读写。如果文件已经存在,将文件指针指向文件头并将文件大小截为零,即删除所有文件已有的内容。如果该文件不存在则尝试创建它,仅能用于本地文件
    x 创建并以写入方式打开,将文件指针指向文件头。如果文件已经存在,则fopen()调用失败并返回false,并生成一条E_WARNING级别的错误信息。如果文件不存在则尝试创建它,仅能用于本地文件
    x+ 创建并以读写方式打开,将文件指针指向文件头。如果文件已经存在,则fopen()调用失败并返回false,并生成一条E_WARNING级别的错误信息。如果文件不存在则尝试创建它,仅能用于本地文件
    a 写入方式打开,将文件指针指向文件末尾。如果该文件已有内容,将从该文件末尾开始追加。如果该文件不存在,函数将创建这个文件
    a+ 写入方式打开,将文件指针指向文件末尾。如果该文件已有内容,将从该文件末尾开始追加或读。如果该文件不存在,函数将创建这个文件
    b 以二进制模式打开文件,用于与其他模式进行连接。如果文件系统能够区分二进制文件和文本文件,你可能会用到它。例如在Windows系统中可以分区,而Unix系统则不分区。这个模式是默认的模式
    t 以文本模式打开文件,这个模式也只是Windows系统下的一个选项,不推荐使用

    2、写入文件
    fwrite(): 将字符串写入到文件中,参数1为fopen打开的文件资源,参数2为要写入的内容,参数3是写入到第length个 字符时停止写入。
    代码示例:

    $file = "demo.txt";
    $handler = fopen($file,"r") or die('Could not open ' .$file);  //以只读模式打开
    //循环10次写入
    for($i=0;$i<10;$i++){
      fwrite($handler,$i ."-Hello world\n");
    }
    fclose($handler);   //关闭指针资源
    
    

    3、读取文件内容

    读取文件的内容函数,如下表

    函数 描述
    fread() 读取打开的文件
    file_get_contents() 将文件读入字符串
    fgets() 从打开的文件中返回一行
    fgetc() 从打开的文件中返回字符
    file() 把文件读入一个数组中
    readfile() 读取一个文件,并输出到输出缓冲

    fread()

    feof():判断一个文件指针是否位于文件的结束处

    代码示例:

    $file = "test.txt";
    $handle = fopen($file,"r") or die("文件打开失败");
    $contents = fread($handle,50);          //从文件读取前50个字节
    echo $contents;
    
    /**从文件中读取全部内容存入到一个变量中,每次读取一部分,循环读取**/
    $file = "./photos/7141730.png";        //二进制文件
    $handle = fopen($file,"rb") or die("文件打开失败");
    $contents = "";
    while(!feof($handle)){                //判断文件是否结尾
        $contents .= fread($handle,1024);
    }
    fclose($handle);
    echo $contents;
    
    /**另一种从文件中读取全部内容的方法**/
    $file = "test.txt";
    $handle = fopen($file,"r") or die("文件打开失败");
    $contents = fread($handle,filesize($file));
    fclose($handle);
    echo $contents;
    

    file_get_contents() 如果只是将一个文件的内容读到一个字符串中,file_get_contents()性能要高一些

    fgets()和fgetc()
    代码示例:

    $file = "./test.txt";
    $handle = fopen($file,"r") or die("文件打开失败");
    while(!feof($handle)){
      $contents = fgets($handle,4096);
      echo $contents . "<br/>";          //输出每一行
    }
    fclose($handle);
    
    $handle = fopen($file,"r") or die("文件打开失败");
    while(false !== ($char = fgetc($handle))){
      echo $char . "<br/>";              //输出单个字符
    }
    fclose($handle);
    

    file():与file_get_contents()类似,不需要使用fopen()打开文件。它可以把整个文件读入到一个数组中。数组中的每个元素对应文件中的相应的行,各元素由换行符分隔,同时换行符仍附加在每个元素的末尾。

    代码示例:

    echo "<pre>";
    print_r(file("test.txt"));
    echo "</pre>";
    

    readfile():该函数可以读取指定的文件,立即输出到输出缓冲区,并返回读取的字节数,不需要使用fopen()打开文件。

    代码示例:

    readfile("test.txt");
    

    4、访问远程文件

    • 对远程文件进行读操作
      代码示例:
    //通过http打开远程文件    只读模式
    $file = fopen("http://www.baidu.com","r") or die("打开远程文件失败");
    //循环从文件中读取的内容
    while(!feof($file)){
      $line = fgets($file,1024);                    //每读取一行
      //如果找到远程文件的标题标记则取出标题,并退出循环,不在读取文件
      if(preg_match("/<title>(.*)<\/title>/",$line,$out)){
          $title = $out[1];
          break;
      }
    }
    fclose($file);
    echo $title;
    
    • 对远程文件进行写操作
    //在远程服务器上创建文件,以写的模式打开
    $file = fopen("ftp://user:password@ftp.域名.net/path/file","w");
    //将一个字符串写入到远程服务器中
    fwrite($file,"hello world");
    //关闭文件资源
    fclose($file);
    

    5、文件的锁定机制
      多个客户端用户在同一时刻对服务器上的同一文件访问的情况下,如果一个用户正向文件中写入数据,当还没有写完时,其他用户在这一时刻也向这个文件中写入数据,就会造成数据写入混乱。还有,当用户没有将数据写完,其他用户就去获取这个文件的内容,也会得到残缺的数据。
    flock():可以对文件使用锁定机制
    代码示例:

    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
    <?php
    //声明一个变量保存文件名,在这个文件中保存留言信息
    $filename = "text_data.txt";
    
    //判断用户是否按下提交按钮,用户提交后则条件成功
    if(isset($_POST['sub'])){
        //接收表单内容,并整合为一条,使用'||'分隔,使用'<|>'结尾
        $message = $_POST['username'] . "||" . $_POST['title'] . "||" . $_POST['mess'] . "<|>";
        writeMessage($filename,$message);      //调用自定义函数,将信息写入文件
    }
    
    //判断文件是否存在,如果存在,读取数据
    if(file_exists($filename)){
        readMessage($filename);
    }
    /**
    * 自定义一个函数,用于向文件中写入数据
    * @param $filename 文件名
    * @param $message  写入的内容
    */
    function writeMessage($filename,$message){
        $fp = fopen($filename,"a");          //以追加的模式打开文件
        if(flock($fp,LOCK_EX)){              //进行排他型锁定(独占锁定)
            fwrite($fp,$message);            //写入文件
            flock($fp,LOCK_UN);              //释放锁定
        }else{
            echo "不能锁定文件";
        }
        fclose($fp);                        //关闭文件资源
    }
    
    /**
    * 自定义函数,用来遍历读取文件
    * @param $filename  文件名
    */
    function readMessage($filename){
        $fp = fopen($filename,"r");              //以只读模式打开文件
        flock($fp,LOCK_SH);                      //建立文件的共享锁定
        $buffer = "";
        while(!feof($fp)){
            $buffer .= fread($fp,1024);          //读出数据后追加到$buffer变量中
        }
        $data = explode("<|>",$buffer);          //将数据转换为数组,以"<|>"分隔
    
        //遍历数组,以html格式输出
        foreach($data as $line){
            //将每行数据再分隔
            @list($username,$title,$message) = explode("||",$line);
            //判断每部分是否为空
            if($username != "" && $title != "" && $message != ""){
                echo $username . '说:';
                echo ' '. $title. ', ';
                echo $message . "<hr>";
            }
        }
        flock($fp,LOCK_UN);                          //释放锁定
        fclose($fp);
    }
    ?>
    
    <form action="" method="post">
        用户名:<input type="text" name="username" size="10" id=""><br/>
        标 题:<input type="text" name="title" size="30" id=""><br/>
        <textarea name="mess" id="" cols="41" rows="4"></textarea>
        <input type="submit" value="留言" name="sub">
    </form>
    </body>
    </html>
    

    6、文件的一些基本操作函数

    函数 语法结构 描述
    copy() copy(来源文件,目的文件) 复制文件
    unlink() unlink(目标文件) 删除文件
    ftruncate() ftruncate(目标文件资源,截取长度 将文件截取到指定长度
    rename() rename(旧文件名,新文件名) 重命名文件或目录

    相关文章

      网友评论

        本文标题:PHP学习笔记之文件系统处理

        本文链接:https://www.haomeiwen.com/subject/qjhjbttx.html