计算代码内打开文件大小的最快方法(PHP)

时间:2011-07-13 05:58:12

标签: php file filesize

我知道PHP中提供了相当多的内置函数来获取文件的大小,其中一些是:filesizestatftell等等。

我的问题在于ftell,这非常有趣,它会从文件中返回文件指针的整数值。

是否可以使用ftell函数获取文件的大小?如果是,那么告诉我怎么做?

情景:

  1. 系统(代码)打开一个模式为“a”的现有文件以附加内容。
  2. 文件指针指向行尾。
  3. 系统将内容更新到文件中。
  4. 系统使用ftell来计算文件的大小。

4 个答案:

答案 0 :(得分:12)

fstat确定没有任何杂技的文件大小:

$f = fopen('file', 'r+');
$stat = fstat($f);
$size = $stat['size'];
使用append(ftell)标志打开文件时,无法使用

"a"。此外,您必须首先使用fseek($f, 0, SEEK_END)搜索文件的末尾。

答案 1 :(得分:2)

ftell()可以告诉您文件中假定的字节数,但实际 的数量是多少。 Sparse files在磁盘上占用的空间少于寻求结束并告知将返回的值。

答案 2 :(得分:0)

感谢@Phihag,将您的信息与fseek以及ftell联系起来,我能够以更好的方式计算尺寸。请参阅此处的代码:http://pastebin.com/7XCqu0WR

<?php
$fp = fopen("/tmp/temp.rock", "a+");

fwrite($fp, "This is the contents");

echo "Time taken to calculate the size by filesize function: ";
$t = microtime(true);
$ts1 = filesize("/tmp/temp.rock") . "\n";
echo microtime(true) - $t . "\n";

echo "Time taken to calculate the size by fstat function:";
$t = microtime(true);
$ts1 = fstat($fp) . "\n";
$size = $ts1["size"];
echo microtime(true) - $t . "\n";

echo "Time taken to calculate the size by fseek and ftell function: ";
$t = microtime(true);
fseek($fp, 0, SEEK_END);
$ts2 = ftell($fp) . "\n";
echo microtime(true) - $t . "\n";

fclose($fp);

/**
OUTPUT:

Time taken to calculate the size by filesize function:2.4080276489258E-5
Time taken to calculate the size by fstat function:2.9802322387695E-5
Time taken to calculate the size by fseek and ftell function:1.2874603271484E-5

*/
?>

答案 3 :(得分:0)

我写了一个基准来改进这个主题,并且为了避免人们争论某种php / cache,我在另一个过程中创建了唯一文件。

这是我毫无疑问要做的新基准。

测试忽略打开和关闭时间,因为用户要求以最快的方式计算已打开文件的大小。 每个测试运行200个文件。

在单独的过程中创建文件的代码是本文的第一条评论。

<?php
class timeIt
{
    static private $times   = [];
    static function new()
    {
        self::$times[] = hrtime(true);
    }
    static function stop()
    {
        self::$times[] = -1;
    }
    static function dif()
    {
        $dif    = 0;
        $sum    = 0;
        $i      = count(self::$times) - 1;

        if (self::$times[$i] === -1)
            unset(self::$times[$i--]);
        
        for ($i = count(self::$times) - 1; $i > 0; --$i) {
            if (self::$times[$i - 1] === -1) {
                $sum    += $dif;
                $dif    = 0;
                --$i;
                continue;
            }
            $dif    += self::$times[$i] - self::$times[$i - 1];
        }
        return $sum + $dif;
    }
    static function printNReset()
    {
        echo "diffTime:" . self::dif() . "\n\n";
        self::reset();
    }
    static function reset()
    {
        self::$times    = [];
    }
}
function fseek_size_from_current($handle)
{
    $current  = ftell($handle);
    fseek($handle, 0, SEEK_END);
    $size   = ftell($handle);
    fseek($handle, $current);
    
    return $size;
}
function fseek_size_from_start($handle)
{
    fseek($handle, 0, SEEK_END);
    $size   = ftell($handle);
    fseek($handle, 0);
    
    return $size;
}

function uniqueProcessId()
{
    return (string) hrtime(true);
}

function getUniqueForeignProcessFiles($quantity, $size)
{
    $returnedFilenames   = $filenames = [];
    while ($quantity--){
        $filename   = uniqueProcessId();
        $filenames[$filename]   = $size;
        $returnedFilenames[]    = __DIR__ . DIRECTORY_SEPARATOR . $filename;
    }

    $data       = base64_encode(json_encode($filenames));
    $foreignCgi = __DIR__ . DIRECTORY_SEPARATOR . "createFileByNames.php";
    $command    = "php $foreignCgi $data";
    if (shell_exec($command) !== 'ok')
        die("An error ocurred");

    return $returnedFilenames;
}
const FILESIZE  = 20 * 1024 * 1024;

foreach(getUniqueForeignProcessFiles(200, FILESIZE) as $filename){
    $handle = fopen($filename, 'r');
    timeIt::new();
    $size   = fstat($handle)['size'];
    timeIt::new();
    timeIt::stop();
    fclose($handle);
    unlink($filename);
}
echo "**fstat**\n";
timeIt::printNReset();

foreach(getUniqueForeignProcessFiles(200, FILESIZE) as $filename){
    $handle = fopen($filename, 'r');
    timeIt::new();
    $size   = fseek_size_from_start($handle);
    timeIt::new();
    timeIt::stop();
    fclose($handle);
    unlink($filename);
}
echo "**fseek with static/defined**\n";
timeIt::printNReset();


foreach(getUniqueForeignProcessFiles(200, FILESIZE) as $filename){
    $handle = fopen($filename, 'r');
    timeIt::new();
    $size   = fseek_size_from_current($handle);
    timeIt::new();
    timeIt::stop();
    fclose($handle);
    unlink($filename);
}
echo "**fseek with current offset**\n";
timeIt::printNReset();


foreach(getUniqueForeignProcessFiles(200, FILESIZE) as $filename){
    $handle = fopen($filename, 'r');
    timeIt::new();
    $size   = filesize($filename);
    timeIt::new();
    timeIt::stop();
    fclose($handle);
    unlink($filename);
}
echo "**filesize after fopen**\n";
timeIt::printNReset();

foreach(getUniqueForeignProcessFiles(200, FILESIZE) as $filename){
    timeIt::new();
    $size   = filesize($filename);
    timeIt::new();
    timeIt::stop();
    unlink($filename);
}
echo "**filesize no fopen**\n";
timeIt::printNReset();

包含20MB文件的结果,时间以纳秒为单位

fstat diffTime:2745700

具有静态/已定义的功能 diffTime:1267400

使用当前偏移量进行搜索 diffTime:983500

打开后的文件大小 diffTime:283052500

文件大小没有打开 diffTime:4259203800

文件大小为1MB,时间以纳秒为单位:

fstat diffTime:1490400

使用静态/已定义的功能 diffTime:706800

使用当前偏移量进行搜索 diffTime:837900

打开后的文件大小 diffTime:22763300

文件大小没有打开 diffTime:216512800

以前,此答案还有另一个基准,我删除了算法,以使此答案更清晰。 该算法使用了由自己的进程创建的文件,并且假设是:

ftell + fseek fstat ['size'] 的时间,一半,即使在另一个函数中,并且两次调用这两个函数。 fstat是 速度较慢,因为它不仅包含文件大小,还包含更多信息, 因此,如果您需要代码旁边的其他信息,请检查 更改,只需坚持使用fstat。

当前基准表明该假设有效,即: **对于1-20 MB的文件,fseek + ftell ++比 fstat 快2-2.8倍。

随时运行您的基准测试并分享您的结果。