php

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

2017-01-12  本文已影响24人  akon2016

导语####

任何类型的变量,都是在程序运行期间才将数据加载到内存中的,并不能持久保存。如果需要将数据长久保存起来,以便后期程序再次运行时还可以使用,存储的基本方法通常有两种:将需要持久化的数据保存到普通文件或数据库中。而对文件的处理因为比较繁琐,所以并不是用来持久储存数据的首选,但在任何计算机设备中,文件都是必需的对象,尤其是在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()中第二个参数可以使用的文件模式

模式 描述
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(旧文件名,新文件名) 重命名文件或目录
上一篇下一篇

猜你喜欢

热点阅读