[PHP] 使用ftell和fseek函数直接定位文件位置获取部分数据
2023-02-18 15:41:28 时间
对于大文件只获取部分数据很有用
1.使用ftell函数可以获取当前指针的字节位置
2.使用fseek函数可以直接定位到指定的位置
3.读取指定字节的数据就可以部分获取文件内容了
<?php class FileStream { private $fp = null; private $mode = 'r'; private $context = null; private $readonly = false; private $writeonly = false; private $appendMode = false; public function __construct($file, $mode = 'r', $context = null) { $mode = trim($mode); if (isset($mode[0])) { $this->mode = strtolower($mode); } if ($context) { $this->context = $context; $this->fp = fopen($file, $mode, false, $this->context); } else { $this->fp = fopen($file, $mode); } if (!$this->fp) { throw new Exception('can not open ' . $file); } if ($this->mode == 'r') { $this->readonly = true; } elseif ($this->mode == 'w') { $this->writeonly = true; } elseif ($this->mode[0] == 'a') { $this->appendMode = true; } } public function __destruct() { $this->close(); } public function close() { if (!$this->fp) { fclose($this->fp); $this->fp = null; } } public function read($size) { if ($this->writeonly) { throw new Exception('write only'); } if (!$this->fp) { throw new Exception('stream already closed'); } $buf = fread($this->fp, $size); if ($buf === false) { throw new Exception('read failed'); } return $buf; } public function readLine() { if ($this->writeonly) { throw new Exception('write only'); } if (!$this->fp) { throw new Exception('stream already closed'); } return fgets($this->fp); } public function readAll() { if ($this->writeonly) { throw new Exception('write only'); } if (!$this->fp) { throw new Exception('stream already closed'); } $buf = ''; while (true) { $s = fread($this->fp, 8192); if ($s === false) { throw new Exception('read failed'); } if (!isset($s[0])) { break; } $buf .= $s; } return $buf; } public function write($data) { if ($this->readonly) { throw new Exception('read only'); } if (!$this->fp) { throw new Exception('stream already closed'); } if (fwrite($this->fp, $data) === false) { throw new Exception('write failed'); } } public function tell() { if ($this->appendMode) { throw new Exception('tell can not work on appendmode'); } if (!$this->fp) { throw new Exception('stream already closed'); } $p = ftell($this->fp); if ($p === false) { throw new Exception('tell failed'); } return $p; } public function seek($position) { if ($this->appendMode) { throw new Exception('seek can not work on seekmode'); } if (!$this->fp) { throw new Exception('stream already closed'); } if (fseek($this->fp, $position) !== 0) { throw new Exception('seek failed'); } } } $stream=new FileStream("1.log"); $start=0; $end=0; //获取开始和结束的字节位置 while($ln=$stream->readLine()){ if($ln=="3333333333333\r\n"){ $start=$stream->tell(); } if($ln=="5555555555555\r\n"){ $end=$stream->tell(); } } var_dump($start,$end); //直接定位到开始的字节位置 $stream->seek($start); //读取指定字节数的数据 $res=$stream->read($end - $start); var_dump($res);
1.log的内容
2.获取部分结果
相关文章
- .net 温故知新:【10】.NET ORM框架EFCore使用入门之CodeFirs、DBFirst
- 一次 Redis 事务使用不当引发的生产事故
- 安卓项目五子棋代码详解(三)
- 安卓项目五子棋代码详解(二)
- 安卓项目五子棋代码详解(一)
- 【深入浅出Seata原理及实战】「入门基础专题」探索Seata服务的AT模式下的分布式开发实战指南(2)
- Nexus私有maven库部署和使用
- 【深入浅出Seata原理及实战】「入门基础专题」带你透析认识Seata分布式事务服务的原理和流程(1)
- 【SpringBoot实战专题】「开发实战系列」从零开始教你舒服的使用RedisTemplate操作Redis数据
- Kotlin学习快速入门(12)—— 位运算符
- Spring Boot命令指定环境启动jar包
- 【Redis 技术探索】「数据迁移实战」手把手教你如何实现在线 + 离线模式进行迁移 Redis 数据实战指南(scan模式迁移)
- 【Redis 技术探索】「数据迁移实战」手把手教你如何实现在线 + 离线模式进行迁移Redis数据实战指南(离线同步数据)
- Window系统的mysql数据库定时备份
- 【SpringBoot实战专题】「开发实战系列」从零开始教你舒服的使用RedisTemplate操作Redis数据
- 【开源库推荐】#4 Poi-办公文档处理库
- 【Redis技术探索】「数据迁移实战」手把手教你如何实现在线+离线模式进行迁移Redis数据实战指南(在线同步数据)
- Kotlin学习快速入门(11)—— 枚举类的使用
- 【深入浅出Sentinel原理及实战】「基础实战专题」零基础实现服务流量控制实战开发指南(2)
- TornadoFx的TableView组件使用