PHP读取大文件末尾N行的高效方法

小文件几兆以内大小,都可以通过 file() 函数,将文件按行读入数组,在用 array_pop 取得最后一行,就可以了。
但是对于很大的文本文件来说,机器内存不够大,或者 php 本身 memory_limit 有限制,这个办法就不适用了,即使强行不限制,效率也是非常低的。

没有办法了吗?当然有,不过没有现成的函数了,需要自己动手了。

这里需要用到文件指针,通俗的讲吧,PHP 中通过 fopen 打开一个文件,这时候还没有读取文件,这时候指向的是文件开头,指针位置也就是 0,当你通过 fgets 或者 fgetc 从文件中读取内容的时候,你读多少,指针也相应往前进多少,这也是

while(!feof($fp)){
$data.=fgets($fp,4096);
}

得以实现的原理,即 fgets 是从当前指针位置向后读取指定长度的字符串,直到遇见换行符为止。

那么可不可以控制指针的位置到倒数第 N 行位置呢?很遗憾,没有,但是可以将指针直接移动到末尾,并倒退 N 个位置,通过 fseek() 函数。

我们先将指针移动到末尾,并向后倒退 2 个位置,通过 fgetc 读取一个字符,判断这个字符是不是 “\n” 也就是换行符,如果不是换行符,那么继续倒退一个位置再次判断,直到我们倒退到上一行的结尾换行符为止,直接使用 fgets 将一整行都取出来即可。这里面用到两个 while 循环,外层循环控制需要取得的行数,内层循环控制 fseek 动作。

函数如下:

/**
 * 取文件最后$n行
 * @param string $filename 文件路径
 * @param int $n 最后几行
 * @return mixed false表示有错误,成功则返回字符串
 */
function FileLastLines($filename,$n){
    if(!$fp=fopen($filename,'r')){
        echo "打开文件失败,请检查文件路径是否正确,路径和文件名不要包含中文";
        return false;
    }
    $pos=-2;
    $eof="";
    $str="";
    while($n>0){
        while($eof!="\n"){
            if(!fseek($fp,$pos,SEEK_END)){
                $eof=fgetc($fp);
                $pos--;
            }else{
                break;
            }
        }
        $str.=fgets($fp);
        $eof="";
        $n--;
    }
    return $str;
}
echo nl2br(FileLastLines('sss.txt',4));

via: http://www.thinkphp.cn/topic/4127.html

约瑟夫环

是一个数学的应用问题:已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。

要求输入:n,k,m

输出:退出顺序

<?php
//$n 人数 $k 开始位置  $m 要数得数字
function array_f($n,$k,$m){
    for($i=1; $i <= $n ; $i++){
        $oldArr[] = $i;
    }    
    for ($i=0;$i<$k-1;$i++){
        $num = array_shift($oldArr);
        $oldArr[] = $num;
    }
    for($i=0;$i<$n;$i++){
        for($j=0;$j<$m-1;$j++){
            $num = array_shift($oldArr);
            $oldArr[] = $num;
        }
        $newArr[] = array_shift($oldArr);
    }
    var_dump($newArr);
}
array_f(6,2,3);

 

使用 PHP 实现冒泡排序,将数组 $a=array() 安装从小到大的方式进行排序

在要排序的一数组中,对当前还未排序好的范围内的全部数,自前向后对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的数往上冒。

即:每当两相邻的数比较后发现它们的排序与排序要求相反时,就将他们互换。

<?php
$arr = [1,43,6,7,3,5,78];
function bubbleSort ($arr) {
    $num = count($arr);
    $temp;
    for ($i=0; $i<$num-1; $i++){
        for ($j=0; $j<$num-1-$i; $j++){
            if ($arr[$j] > $arr[$j+1]){
                $temp = $arr[$j];
                $arr[$j] = $arr[$j+1];
                $arr[$j+1] = $temp;
            }
        }
    }
    return $arr;
}
print_r (bubbleSort($arr));

 

使用 PHP 秒速快速排序算法

基本思想:选择一个基准元素,通常选择第一个元素,通过一趟扫描,将待排序列分为两个部分,一部分比基准元素小(做数组),一部分大于等于基准元素组(右数组),此时基准元素在其排好序后的正确位置,然后再用同样的方法递归地排序划分的两部分。

可以看到,这种方法是把大问题转变为小问题的方法,使用递归实现。

image

<?php
//递归函数的特点有两个
//1.要有递归出口,应该放到递归函数的最前面
//2.要有递归调用
function quick sort ($arr) {
    //递归出口判断要放在最前面
    if (count($arr) <= 1){
        return $arr;
    }
    //把第一个元素从数组中弹出去放在一个变量中
    $key = array_shift($arr);
    //把刚才弹出的第一个元素(基准元素)存到一个数组中
    $key_arr = array($key);
    //定义两个空数组,给左边和右边的数组进行初始化。
    $left_arr = array();
    $right_arr = array();
    foreach ($arr as $value){
        if($value < $key){
            $left_arr[] = $value;
        }else{
            $right_arr[] = $value;
        }
    }
    //这里就是递归调用
    return array_merge(quick_sort($left_arr), $key_arr, quick_sort($right_arr));
}

 

优化 MySQL 数据库的方法

1. 选取最实用的字段属性,尽可能减少定义字段长度,尽量把字段设置NOT NULL,例如“省份,性别”,最好设置为ENUM

2. 使用连接(JOIN)来代替子查询

3. 使用联合(UNION)来代替手动创建临时表

4. 事务处理

5. 锁表,优化事务处理

6. 使用外键,优化锁定表

7. 建立索引

8. 优化查询语句

PHP值传递和引用传递的区别

值传递是将变量的值复制一份,改变一个变量的值而不影响另一个变量的值。

引用传递是将变量的引用关系复制一份,改变一个变量的值另一个变量的值也会随之改变。

值传递:

形式:

[php]
$v1 = 1;
$v2 = $v1;
[/php]

含义:将变量$v1的值复制一份,然后赋值给$v2,$v1和$v2具有两相同的值,但$v1和$v2是相互独立的,互相没有关系的两个变量。

image

引用传递:

形式:

[php]
$v1 = 1;
$v2 = &$v1;
[/php]

含义:将变量$v1跟其数据之间的关系,复制一份,然后将关系应用到$v2上。此时,$v1和$v2都有了一个共同的特性:指向同一数据(区)。改变一个变量的值都会影响另一个变量的值。

image

PHP判断上传文件是否为图片且保存为唯一命名

[php]
<?php
header("content-type:text/html;charset=utf-8");
$arr_ext = array("jpg","png","gif");
$index = strrpos($_FILES[‘upload’][‘name’],".");
$ext = substr($_FILES[‘upload’][‘name’],$index+1);
if(!in_array($ext,$arr_ext))
{
echo "上传的文件不是图像";
exit();
}else
{
$src = $_FILES[‘upload’][‘tmp_name’];
$dst = "./upload/".uniqid().".$ext";
move_uploaded_file($src,$dst);
echo "上传文件成功";
}
?>
[/php]

[html]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>判断上传文件是否为图片,为保存为唯一命名</title>
</head>
<body>
<form name="form1" method="post" enctype="multipart/form-data" action="upload2.php">
上传图片:<input type="file" name="upload">
<input type="submit" value="提交表单">
</form>
</body>
</html>
[/html]