文件 FIFO队列
<?php
/**
* Filefifo.php 文件型FIFO队列
*/
class Filefifo
{
/**
* $_file_data, 数据文件的路径
*/
private $_file_data = ''; /**
* $_file_idx, 索引文件的路径
*/
private $_file_idx = ''; /**
* $_file_idx_bak, 索引备份文件的路径, 防止意外断电等导致索引文件破坏
*/
private $_file_idx_bak = ''; /**
* $_f_data, 数据文件的句柄
*/
private $_f_data; /**
* $_f_idx, 索引文件句柄
*/
private $_f_idx; /**
* $_f_idx_bak, 索引备份文件句柄
*/
private $_f_idx_bak; private static $_instance = array(); public static function instance($file)
{
if (! isset(self::$_instance[$file])) {
self::$_instance[$file] = new self($file);
}
return self::$_instance[$file];
} public function __construct($file)
{
$this->attach($file);
} public function __destruct()
{
$this->detach();
} /**
* attach, 挂接一个队列文件
*/
public function attach($file)
{
/**
* 初始化文件
*/
$this->_file_data = $file;
$this->_file_idx = "{$file}.idx";
$this->_file_idx_bak = "{$file}.idx.bak"; if (! file_exists($file)) {
$f = fopen($file, 'w+');
fclose($f); if (file_exists($this->_file_idx)) unlink($this->_file_idx);
if (file_exists($this->_file_idx_bak)) unlink($this->_file_idx_bak);
} $idx_data_bak = ''; /**
* 有备份则读取备份数据,无备份则创建空备份文件
*/
if (file_exists($this->_file_idx_bak)) {
$idx_data_bak = file_get_contents($this->_file_idx_bak);
} else {
$f = fopen($this->_file_idx_bak, 'w+');
fclose($f);
} /**
* 不存在索引文件则创建,并从索引备份中恢复
*/
if (! file_exists($this->_file_idx)) {
$f = fopen($this->_file_idx, 'w+');
if ($idx_data_bak) fwrite($f, $idx_data_bak);
fclose($f);
} else {
if (! file_get_contents($this->_file_idx) && $idx_data_bak) {
file_put_contents($this->_file_idx, $idx_data_bak);
}
} $this->_f_data = fopen($this->_file_data, 'a+b');
$this->_f_idx = fopen($this->_file_idx, 'rw+b');
$this->_f_idx_bak = fopen($this->_file_idx_bak, 'rw+b');
} /**
* detach, 分离当前队列文件
*/
private function detach()
{
if ($this->_f_data) fclose($this->_f_data);
if ($this->_f_idx) fclose($this->_f_idx);
if ($this->_f_idx_bak) fclose($this->_f_idx_bak);
$this->_f_data = NULL;
$this->_f_idx = NULL;
$this->_f_idx_bak = NULL;
} /**
* rewind, 设置到队列头
*/
public function rewind()
{
flock($this->_f_idx, LOCK_EX);
ftruncate($this->_f_idx, 0);
ftruncate($this->_f_idx_bak, 0);
flock($this->_f_idx, LOCK_UN);
} /**
* end, 设置到队列尾
*/
public function end()
{
flock($this->_f_idx, LOCK_EX);
// 重新计算数据文件行数
$line = $this->len();
$file_len = filesize($this->_file_data);
fseek($this->_f_data, $file_len); ftruncate($this->_f_idx, 0);
rewind($this->_f_idx);
fwrite($this->_f_idx, $file_len.",".$line); ftruncate($this->_f_idx_bak, 0);
rewind($this->_f_idx_bak);
fwrite($this->_f_idx_bak, $file_len.",".$line); flock($this->_f_idx, LOCK_UN);
} /**
* pos, 获取当前队列位置
*/
public function pos()
{
flock($this->_f_idx, LOCK_EX);
rewind($this->_f_idx);
$data_idx = fgets($this->_f_idx, 1024);
$data_idx = explode(",", $data_idx);
$pos = (int) trim($data_idx[0]);
$line = isset($data_idx[1]) ? (int) trim($data_idx[1]) : 0;
flock($this->_f_idx, LOCK_UN); return array('pos' => $pos, 'line' => $line); } /**
* len, 获取队列总长度
*/
public function len()
{
flock($this->_f_data, LOCK_EX); $old_pos = ftell($this->_f_data);
rewind($this->_f_data);
$line = 0;
while (fgets($this->_f_data, 1024) !== FALSE) $line ++;
fseek($this->_f_data, $old_pos); flock($this->_f_data, LOCK_UN); return $line;
} /**
* pop, 先进先出顺序弹出多条记录
*
* @param int $num, 一次性返回多条记录
* @param array $cur_pos, 返回当前记录所在偏移量、文件行位置信息
* @return array | boolean, 返回字符串数组记录,失败则返回FALSE
*/
public function pop($num = 1, & $cur_pos = array())
{
$num = $num < 1 ? 1 : $num; /**
* 锁定索引文件,读取索引内容
*/
flock($this->_f_idx, LOCK_EX);
rewind($this->_f_idx);
$data_idx = fgets($this->_f_idx, 1024);
$data_idx = explode(",", $data_idx);
$pos = (int) trim($data_idx[0]);
$line = isset($data_idx[1]) ? (int) trim($data_idx[1]) : 0; $data_all = array();
for ($i = 0; $i < $num; $i ++) {
/**
* 根据索引位置,读取数据文件
*/
fseek($this->_f_data, $pos);
$data = fgets($this->_f_data, 8192); /**
* 如果读取成功则更新索引记录
*/
if ($data !== FALSE) {
$pos = ftell($this->_f_data);
$line ++; rewind($this->_f_idx);
ftruncate($this->_f_idx, 0);
fwrite($this->_f_idx, "{$pos},{$line}"); rewind($this->_f_idx_bak);
ftruncate($this->_f_idx_bak, 0);
fwrite($this->_f_idx_bak, "{$pos},{$line}");
} else {
break;
} $data_all[$line] = $data;
} flock($this->_f_idx, LOCK_UN); $cur_pos = array(
'pos' => $pos,
'line' => $line,
); return $data_all ? $data_all : FALSE;
} /**
* push, 队尾压入多条记录
*
* @param string | array $data, 字符串数据,不能包含回车换行,否则会追加多条记录
* @return int, 返回插入的记录条数
*/
public function push($data)
{
if (! is_array($data)) {
$data = array($data);
} $count = 0; /**
* 锁定数据文件,追加记录
*/
flock($this->_f_data, LOCK_EX);
if (is_array($data)) {
foreach ($data as $line) {
fwrite($this->_f_data, $line."\r\n");
$count ++;
}
}
flock($this->_f_data, LOCK_UN); return $count; } /**
* del, 清空一个队列
*/
public function del()
{
$this->detach();
unlink($this->_file_data);
unlink($this->_file_idx);
unlink($this->_file_idx_bak); return TRUE;
}
}
使用文本文件作为FIFO队列,支持多进程操作同一文件,支持现场恢复。适合处理QQ用户包文本等按行分割的文件。实测每秒入队14万行,出队1万行。
主要操作
初始化一个队列
$fifo = Filefifo::instance(‘文件路径’);
出队
$data = $fifo->pop(‘要出队的行数,默认1’);
入队
$fifo->push(‘要入队的数据’)
其他操作
挂接一个数据文件
$fifo->attach(‘文件路径’)
分离当前队列文件
$fifo->detach()
移动到队列头
$fifo->rewind()
到队列尾
$fifo->end()
获取当前位置
$fifo->pos();
获取队列总长度(文件总行数)
$fifo->len()
删除队列
$fifo->del();
demo:
<?php
$file = ‘qq.txt’;
$list = Filefifo::instance($file);
$start = microtime(TRUE); // push
for ($i = 0; $i < 1000; $i ++) {
$list->push($i);
}
// pop
do {
$data = $list->pop();
} while ($data !== FALSE); echo (microtime(TRUE) - $start ) * 1000; ?>
文件 FIFO队列的更多相关文章
- FIFO队列算法的C程序实现
头文件:Queue.h #ifndef _Queue_H #define _Queue_H typedef struct QueueDef_ //队列对象定义 { u16 front; //队列头部 ...
- C#内存映射文件消息队列实战演练(MMF—MQ)
一.课程介绍 本次分享课程属于<C#高级编程实战技能开发宝典课程系列>中的一部分,阿笨后续会计划将实际项目中的一些比较实用的关于C#高级编程的技巧分享出来给大家进行学习,不断的收集.整理和 ...
- zookeeper应用 - FIFO 队列 分布式队列
使用ZooKeeper实现的FIFO队列,这个队列是分布式的. package fifo; import java.util.Collections; import java.util.List; i ...
- STL队列 之FIFO队列(queue)、优先队列(priority_queue)、双端队列(deque)
1.FIFO队列 std::queue就是普通意思上的FIFO队列在STL中的模版. 1.1主要的方法有: (1)T front():访问队列的对头元素,并不删除对头元素 (2)T back(): ...
- FIFO队列(First In First Out)和优先队列
queue<类型名> q; q.size() - 返回队列中元素个数 q.empty() - 若队列为空,返回true ,否则返回false q.pop() - 删除队首元素,但不返回其值 ...
- FIFO队列 ADT接口 数组实现
FIFO.h (接口) #include "Item.h" #include <stdlib.h> typedef struct STACKnode *link; st ...
- Tensorflow读取文件到队列文件
TensorFlow读取二进制文件数据到队列 2016-11-03 09:30:00 0个评论 来源:diligent_321的博客 收藏 我要投稿 TensorFlow是一种 ...
- redis怎么实现FIFO队列思想
队列(FIFO)通过插入和弹出不同方向操作就可以实现,栈(FILO)插入和弹出相同方向的操作就可以实现:
- UOJ222 NOI2016 区间 线段树+FIFO队列
首先将区间按长度排序后离散化端点(这里的“长度”指的是离散化之前区间的实际长度) 然后模拟一个队列,区间按排好的顺序依次进入,直到某个点被覆盖了M次.之后依次出队,直到所有点都被覆盖小于M次 修改和询 ...
随机推荐
- 【NOIP2010】引水入城
以前一直以为是什么高端DP,看了题解才发现是水题,老是这样看题解才能写出来到赛场上怎么办嘛QAQ 原题: 在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠.该国的行政区划十分特殊,刚好 ...
- 排序算法总结(二)归并排序【Merge Sort】
一.归并排序原理(Wikipedia) 归并排序本质是分治思想的应用,并且各层分治递归可以同时进行 1.申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列 2.设定两个指针,最初位置 ...
- HTML DOM参考手册
HTML DOM是HTML Document Object Model(文档对象模型)的缩写,HTML DOM则是专门适用与HTML/XHTML的文档对象模型.熟悉软件开发的人员可以将HTML DOM ...
- 黑马程序员——JAVA基础之Collections和Arrays,数组集合的转换
------- android培训.java培训.期待与您交流! ---------- 集合框架的工具类: Collections : 集合框架的工具类.里面定义的都是静态方法. Col ...
- Linux-SSL和SSH和OpenSSH,OpenSSL有什么区别
ssl是通讯链路的附加层.可以包含很多协议.https, ftps, ..... ssh只是加密的shell,最初是用来替代telnet的.通过port forward,也可以让其他协议通过ssh的隧 ...
- 一次zabbix的渗透
wget http://xxxxxxx:8888/back.py -O /tmp/1.py 写入python反弹马 反弹到vps python /tmp/back.py IP port ...
- 07-Java 中的IO操作
1.Java IO简介: (1)I/O :in \out 即输入与输出.基本功能:读写. (2)IO流:作用:读写设备上的数据,硬盘文件.内存.键盘.网络-- 根据数据的走向,可分为:输入流.输出流. ...
- cacti
http://www.cacti.net/downloads/docs/html/index.html Cacti脚本及模板论坛:http://forums.cacti.net/forum-12.ht ...
- ImportError: cannot import name 'NUMPY_MKL'
>>> import scipy Traceback (most recent call last): File "<stdin>", line 1, ...
- 制作OS X 10.10.3启动安装U盘
http://www.cnblogs.com/Bob-wei/p/4471407.html 1.获得“Install OS X Yosemite.app” 2.准备一个8GB的U盘,用磁盘工具“抹掉” ...