php 文件操作

一、文件/文件夹操作相关命令

fopen
flock:锁定
flock( r e s o u r c e , L O C K E X ) f l o c k ( resource,LOCK_EX) flock( resource,LOCKEX)flock(resource,LOCK_UN);
fgets
feof
rewind:指针回到文件起始位置
readfile:读取文件到输出流,返回读取字符数
fseek:移动指针
fpassthru:读取文件资源的指针后的全部字符到输出流,并返回读取的字符数
opendir
readdir
closedir

LOCK_SH - 共享锁定(读取的程序)。允许其他进程访问该文件。
LOCK_EX - 独占锁定(写入的程序)。防止其他进程访问该文件。
LOCK_UN - 释放一个共享锁定或独占锁定
LOCK_NB - 锁定的情况下避免阻塞其他进程。(基本不用,因为遵守默认不阻塞的策略)

file: 将文件读取到数组中,一行对应一个键数
fread:读取字符
filesize:获取文件大小

touch
mkdir
copy
rename
unlink
rmdir

file_put_contents(’/root/test2.txt’,“测试”,FILE_APPEND|LOCK_EX);

二、文件上传

<?php if ($_FILES['pic']['error'] > 0) { echo '上传错误:'.$_FILES['pic']['error']; } else { echo "文件名:".$_FILES['pic']['name'].'
'; echo "上传类型:".$_FILES['pic']['type'].'
'; echo "文件大小:".($_FILES['pic']['size'] / 1024).' KB
'; echo "临时文件位置:".$_FILES['pic']['tmp_name'].'
'; // 存储 if (!is_dir('./upload')) { mkdir('./upload',true); chmod('./upload',0777); } if (file_exists('./upload/'.$_FILES['pic']['name'])){ unlink('./upload/'.$_FILES['pic']['name']); } touch('./upload/test.txt'); move_uploaded_file($_FILES['pic']['tmp_name'],'./upload/'.$_FILES['pic']['name']); echo "文件存储在: " . real_path('./upload') . $_FILES["pic"]["name"]; } 输出结果: 文件名:account_infos.sql 上传类型:application/octet-stream 文件大小:3.3564453125 KB 临时文件位置:/tmp/phpyLF0mK ## 三、大文件读取1 (废弃) #### 1、通过fgets获取行 ``` $file = 'test.log'; $fp = fopen($file,'r'); $line = 10; $buf = 2048; while(!feof($fp)){ $str = ''; $i=0; for(;$i<$line;$i++){ $str .= fgets($fp); $i++; } print($str); print_r('///'.PHP_EOL); } ``` #### 2、通过fread读取字符 ``` <?php // 通过fread读取字符 $file = $argv[1]; $filesize = filesize($file); if (!$filesize) { echo 'this is an empty file'; } $fp = fopen($file,'r'); $buff = 1024; $readNum = 0; $str = ''; $start = getmicrotime(); while ($readNum < $filesize) { if ($readNum + $buff > $filesize) { $num = $filesize - $readNum; } else { $num = $buff; } $str .= fread($fp,$num); $readNum += $num; echo "pos:".ftell($fp).PHP_EOL; } fclose($fp); echo $str.PHP_EOL.'耗时:'; echo getmicrotime() - $start; function getmicrotime() { $arr = explode(' ',microtime()); return $arr[1] + substr($arr[0],0,5); } ``` 测试:文件大小2.9M 耗时:1.339秒 ![在这里插入图片描述](https://img-blog.csdnimg.cn/560f82f1d7dd43d9bee7697058ba3285.png) #### 3、通过file_get_contents读取 ``` <?php // 通过fread读取字符 $file = $argv[1]; $filesize = filesize($file); if (!$filesize) { echo 'this is an empty file'; } $buff = 1024; $readNum = 0; $str = ''; while ($readNum < $filesize) { if ($readNum + $buff > $filesize) { $num = $filesize - $readNum; } else { $num = $buff; } $str .= file_get_contents($file,false,null,$readNum,$num); $readNum += $num; } echo $str; ``` 测试:文件大小2.9M 耗时:1.338秒 ![在这里插入图片描述](https://img-blog.csdnimg.cn/7352742597334f9991eaa87f5000602d.png) 结论:使用fread和file_get_contents性能基本差不多 ## 三、大文件读取2 +内存分析 视频大小10.4M 通过测试对比发现使用fgets比file_get_contents占用内存小很多,证明内存占用大小和读取文件的字符数成正比,所以如果采用fread理论上可以实现比fgets占用更小的内存 - 方法1:普通方法 直接使用file_get_contents方法 ``` // 展示文件/流大小 function friendShow($bytes, $precision = 2) { $units = array("b", "kb", "mb", "gb", "tb"); $bytes = max($bytes, 0); $pow = floor(($bytes ? log($bytes,1024) : 0) / log(1024,1024)); $pow = min($pow, count($units) - 1); $bytes /= 1 << 10 * $pow; return round($bytes, $precision) . " " . $units[$pow]; } $file = 'test.mp4'; echo 'start memory usage:'.friendShow(memory_get_peak_usage()).PHP_EOL; // $fp = fopen($file,'r'); $content = file_get_contents($file); echo ' memory usage:'.friendShow(memory_get_peak_usage()).PHP_EOL; ``` 初始内存1.8M,完成后内存占用12.06M,效果很不理想 ![在这里插入图片描述](https://img-blog.csdnimg.cn/775136161dc046a0929eb9b4a2570a1a.png) - 方法2 使用fgets按行读取 ``` $file = 'test.mp4'; $fp = fopen($file,'r'); $content = ''; echo 'start memory usage:'.friendShow(memory_get_peak_usage()).PHP_EOL; while(!feof($fp)){ $content .= fgets($fp); } echo ' memory usage:'.friendShow(memory_get_peak_usage()).PHP_EOL; ``` 初始内存1.8M,完成后内存占用12.05M,内存占用情况并没有改善,效果依旧不理想,证明fgets如果读取完所有文件,与file_get_contents的内存占用是一样的 ![在这里插入图片描述](https://img-blog.csdnimg.cn/cd1296fe5b87416292f88974c119fb0a.png) 通过上面的测试,理论上我们有两种方式实现大文件,低内存的方式读写 1、采用fgets读取一行后立即使用file_put_contents写入 2、使用yield异步操作 现在我们开始测试 - 测试1 ``` $file = 'test.mp4'; $dest = 'test2.mp4'; function getContent($file,$dest) { if(file_exists($dest)){ unlink($dest); touch($dest); } else { touch($dest); } $fp = fopen($file,'r'); while(!feof($fp)){ $content = fgets($fp); file_put_contents($dest,$content,FILE_APPEND); } fclose($fp); } echo 'start memory usage:'.friendShow(memory_get_peak_usage()).PHP_EOL; getContent($file,$dest); echo ' memory usage:'.friendShow(memory_get_peak_usage()).PHP_EOL; ``` 结果:内存消耗占用为0 ![在这里插入图片描述](https://img-blog.csdnimg.cn/f0812bfe4049401db12f87fba9c8b53e.png) - 测试2 ``` $file = 'test.mp4'; $dest = 'test2.mp4'; function getGenerator($file,$dest) { if(file_exists($dest)){ unlink($dest); touch($dest); } else { touch($dest); } $fp = fopen($file,'r'); while(!feof($fp)){ yield fgets($fp); } fclose($fp); } echo 'start memory usage:'.friendShow(memory_get_peak_usage()).PHP_EOL; $generator = getGenerator($file,$dest); foreach($generator as $val){ file_put_contents($dest,$val,FILE_APPEND); } echo ' memory usage:'.friendShow(memory_get_peak_usage()).PHP_EOL; ``` 结果跟测试1的结果一致 ![在这里插入图片描述](https://img-blog.csdnimg.cn/5da5f762bbff4eafabc8388ca85f890e.png) - stream_copy_to_stream vs file_put_contents 对比 file_put_contents ``` $file = 'test.mp4'; $dest = 'test2.mp4'; echo 'start memory usage:'.friendShow(memory_get_peak_usage()).PHP_EOL; $content = file_get_contents($file); file_put_contents($dest,$content); echo ' memory usage:'.friendShow(memory_get_peak_usage()).PHP_EOL; ``` 结果: ![在这里插入图片描述](https://img-blog.csdnimg.cn/98e4faf85f974aab923a006c5914c626.png) - stream_copy_to_stream ``` $file = 'test.mp4'; $dest = 'test2.mp4'; echo 'start memory usage:'.friendShow(memory_get_peak_usage()).PHP_EOL; $fp1 = fopen($file,'r'); $fp2 = fopen($dest,'w'); stream_copy_to_stream($fp1,$fp2); echo ' memory usage:'.friendShow(memory_get_peak_usage()).PHP_EOL; ``` 结果: ![在这里插入图片描述](https://img-blog.csdnimg.cn/a66dcb6cbe434166bb64b89c3a7cb011.png) 结论:stream_copy_to_stream默认实现了流读取,并做了优化,基本不占用内存,是大文件复制的首选,但是作用不大,可以用copy取代
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值