Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/252.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PHP x86如何获取>;的文件大小;没有外部程序的2GB文件?_Php_File Io_X86_Large Files_Filesize - Fatal编程技术网

PHP x86如何获取>;的文件大小;没有外部程序的2GB文件?

PHP x86如何获取>;的文件大小;没有外部程序的2GB文件?,php,file-io,x86,large-files,filesize,Php,File Io,X86,Large Files,Filesize,我需要得到一个文件大小超过2GB的文件。(在4.6 GB文件上进行测试)。在没有外部程序的情况下,有没有办法做到这一点 当前状态: filesize(),stat()和fseek()失败 fread()和feof()有效 可以通过读取文件内容获得文件大小(速度非常慢!) 我知道如何在64位平台上获得它(使用fseek($fp,0,SEEK_END)和ftell()),但我需要32位平台的解决方案 解决方案:我已经为此启动了开源项目 大文件工具 大文件工具是在PHP中操作超过2GB的文件(甚

我需要得到一个文件大小超过2GB的文件。(在4.6 GB文件上进行测试)。在没有外部程序的情况下,有没有办法做到这一点

当前状态:

  • filesize()
    stat()
    fseek()
    失败
  • fread()
    feof()
    有效
可以通过读取文件内容获得文件大小(速度非常慢!)

我知道如何在64位平台上获得它(使用
fseek($fp,0,SEEK_END)
ftell()
),但我需要32位平台的解决方案


解决方案:我已经为此启动了开源项目

大文件工具 大文件工具是在PHP中操作超过2GB的文件(甚至在32位系统上)所需的黑客的集合

  • 答复:
  • github:

一种选择是寻找2gb标记,然后从那里读取长度

function getTrueFileSize($filename) {
    $size = filesize($filename);
    if ($size === false) {
        $fp = fopen($filename, 'r');
        if (!$fp) {
            return false;
        }
        $offset = PHP_INT_MAX - 1;
        $size = (float) $offset;
        if (!fseek($fp, $offset)) {
            return false;
        }
        $chunksize = 8192;
        while (!feof($fp)) {
            $size += strlen(fread($fp, $chunksize));
        }
    } elseif ($size < 0) {
        // Handle overflowed integer...
        $size = sprintf("%u", $size);
    }
    return $size;
}
函数getTrueFileSize($filename){ $size=filesize($filename); 如果($size==false){ $fp=fopen($filename,'r'); 如果(!$fp){ 返回false; } $offset=PHP\u INT\u MAX-1; $size=(浮动)$offset; 如果(!fseek($fp,$offset)){ 返回false; } $chunksize=8192; 而(!feof($fp)){ $size+=strlen(fread($fp,$chunksize)); } }elseif($size<0){ //处理溢出的整数。。。 $size=sprintf(“%u”,$size); } 返回$size; } 因此,基本上,它寻求PHP中可表示的最大正符号整数(32位系统为2gb),然后从那时起使用8kb块进行读取(这应该是最佳内存效率与磁盘传输效率的公平折衷)


还要注意,我并没有将
$chunksize
添加到size。原因是,
fread
实际返回的字节可能多于或少于
$chunksize
,这取决于多种可能性。因此,请使用strlen来确定解析字符串的长度。

如果您有FTP服务器,可以使用fsockopen:

$socket = fsockopen($hostName, 21);
$t = fgets($socket, 128);
fwrite($socket, "USER $myLogin\r\n");
$t = fgets($socket, 128);
fwrite($socket, "PASS $myPass\r\n");
$t = fgets($socket, 128);
fwrite($socket, "SIZE $fileName\r\n");
$t = fgets($socket, 128);
$fileSize=floatval(str_replace("213 ","",$t));
echo $fileSize;
fwrite($socket, "QUIT\r\n");
fclose($socket); 

(可在页面上找到注释)

您可能需要为所使用的函数添加一些替代选项,例如调用系统函数,如“dir”/“ls”,并从中获取信息。它们是安全性的主题,当然,您可以检查这些内容,并最终恢复到慢速方法,这只是最后的手段。

这里有一种可能的方法:

它首先尝试使用适合平台的shell命令(Windows shell替换修饰符或*nix/Mac
stat
command)。如果失败,它将尝试COM(如果在Windows上),最后返回到
filesize()

/*
*本软件可根据条款进行修改和分发
*麻省理工学院的执照。
*/
函数filesize64($file)
{
静态$iswin;
如果(!isset($iswin)){
$iswin=(strtoupper(substr(PHP_-OS,0,3))=='WIN');
}
静态$exec_工作;
如果(!isset($exec_works)){
$exec_works=(函数_exists('exec')&&!ini_get('safe_mode')&&&@exec('echo exec')=='exec');
}
//尝试一个shell命令
如果($exec_工作){
$cmd=($iswin)?“对于(\“$file\”)中的%F执行@echo%~zF:“stat-c%s\”$file\”;
@exec($cmd,$output);
if(is_数组($output)和&ctype_数字($size=trim(内爆(“\n”,$output))){
返回$size;
}
}
//尝试Windows COM界面
如果($iswin&&class_存在(“COM”)){
试一试{
$fsobj=new COM('Scripting.FileSystemObject');
$f=$fsobj->GetFile(realpath($file));
$size=$f->size;
}捕获(例外$e){
$size=null;
}
if(ctype_数字($size)){
返回$size;
}
}
//如果一切都失败了
返回filesize($file);
}
当使用IEEE double(大多数系统)时,小于4EB(etabytes=10^18字节)的文件大小适合作为精确数字的double(并且在使用标准算术运算时不应丢失精度)。


使用方法如下:

<?php include("php/size.php"); ?>

在你想要的地方:

<?php showsize("files/VeryBigFile.rar"); ?>


如果你想改进它,欢迎你

一些答案表明,通过检查filesize()是否返回负数,无法可靠地获得32位系统上的文件大小。这是因为,如果32位系统文件大小上的文件大小介于4到6 Gig之间,则会报告一个正数,然后从6到8为负数,然后从8到10为正数,依此类推。从某种意义上说,它是循环的

因此,您无法使用在32位系统上可靠工作的外部命令

但是,一个非常有用的工具是能够检查文件大小是否大于某个大小,并且即使在非常大的文件上也可以可靠地执行此操作

下面的代码试图读取50兆,并尝试读取一个字节。它在我的低规格测试机上运行非常快,即使大小远远大于2 Gig,也能可靠地工作

您可以使用此选项检查文件是否大于2147483647字节(2147483648在32位系统上为max int),然后以不同方式处理该文件或让您的应用程序发出警告

function isTooBig($file){
        $fh = @fopen($file, 'r');
        if(! $fh){ return false; }
        $offset = 50 * 1024 * 1024; //50 megs
        $tooBig = false;
        if(fseek($fh, $offset, SEEK_SET) === 0){
                if(strlen(fread($fh, 1)) === 1){
                        $tooBig = true;
                }
        } //Otherwise we couldn't seek there so it must be smaller

        fclose($fh);
        return $tooBig;
}

我编写了一个函数,它可以精确地返回文件大小,而且速度非常快:

function file_get_size($file) {
    //open file
    $fh = fopen($file, "r"); 
    //declare some variables
    $size = "0";
    $char = "";
    //set file pointer to 0; I'm a little bit paranoid, you can remove this
    fseek($fh, 0, SEEK_SET);
    //set multiplicator to zero
    $count = 0;
    while (true) {
        //jump 1 MB forward in file
        fseek($fh, 1048576, SEEK_CUR);
        //check if we actually left the file
        if (($char = fgetc($fh)) !== false) {
            //if not, go on
            $count ++;
        } else {
            //else jump back where we were before leaving and exit loop
            fseek($fh, -1048576, SEEK_CUR);
            break;
        }
    }
    //we could make $count jumps, so the file is at least $count * 1.000001 MB large
    //1048577 because we jump 1 MB and fgetc goes 1 B forward too
    $size = bcmul("1048577", $count);
    //now count the last few bytes; they're always less than 1048576 so it's quite fast
    $fine = 0;
    while(false !== ($char = fgetc($fh))) {
        $fine ++;
    }
    //and add them
    $size = bcadd($size, $fine);
    fclose($fh);
    return $size;
}

下面的代码适用于任何版本的PHP/OS/Webserver/Platform上的任何文件大小

// http head request to local file to get file size
$opts = array('http'=>array('method'=>'HEAD'));
$context = stream_context_create($opts);

// change the URL below to the URL of your file. DO NOT change it to a file path.
// you MUST use a http:// URL for your file for a http request to work
// SECURITY - you must add a .htaccess rule which denies all requests for this database file except those coming from local ip 127.0.0.1.
// $tmp will contain 0 bytes, since its a HEAD request only, so no data actually downloaded, we only want file size
$tmp= file_get_contents('http://127.0.0.1/pages-articles.xml.bz2', false, $context);

$tmp=$http_response_header;
foreach($tmp as $rcd) if( stripos(trim($rcd),"Content-Length:")===0 )  $size= floatval(trim(str_ireplace("Content-Length:","",$rcd)));
echo "File size = $size bytes";

// example output
File size = 10082006833 bytes

我为Linux/Unix找到了一个很好的slim解决方案,它只需要使用32位php获得大文件的文件大小

$file = "/path/to/my/file.tar.gz";
$filesize = exec("stat -c %s ".$file);
您应该将
$filesize
作为字符串处理。如果文件大小大于PHP_int_MAX,则尝试强制转换为int将导致filesize=PHP_int_MAX

但是,尽管作为字符串处理,以下人类可读的算法仍然有效:

formatBytes($filesize);

public function formatBytes($size, $precision = 2) {
    $base = log($size) / log(1024);
    $suffixes = array('', 'k', 'M', 'G', 'T');
    return round(pow(1024, $base - floor($base)), $precision) . $suffixes[floor($base)];
}
因此,对于大于4 Gb的文件,我的输出为:

4.46G
这适用于我在Windows机箱上的操作

我在这里查看了bug日志:发现这个
formatBytes($filesize);

public function formatBytes($size, $precision = 2) {
    $base = log($size) / log(1024);
    $suffixes = array('', 'k', 'M', 'G', 'T');
    return round(pow(1024, $base - floor($base)), $precision) . $suffixes[floor($base)];
}
4.46G
$file_size=sprintf("%u",filesize($working_dir."\\".$file));
if($size < 0) $size = pow(2,32) + $size;
$size = pow(2,32) * $loops_count + $size;
composer install jkuchar/BigFileTools
<?php
$file = BigFileTools\BigFileTools::createDefault()->getFile(__FILE__);
echo $file->getSize() . " bytes\n";
$sizeInBytes = $file->getSize();
$sizeInMegabytes = $sizeInBytes->toBigDecimal()->dividedBy(1024*1024, 2, \Brick\Math\RoundingMode::HALF_DOWN);    
echo "Size is $sizeInMegabytes megabytes\n";
| Driver           | Time (s) ↓          | Runtime requirements | Platform 
| ---------------  | ------------------- | --------------       | ---------
| CurlDriver       | 0.00045299530029297 | CURL extension       | -
| NativeSeekDriver | 0.00052094459533691 | -                    | -
| ComDriver        | 0.0031449794769287  | COM+.NET extension   | Windows only
| ExecDriver       | 0.042937040328979   | exec() enabled       | Windows, Linux, OS X
| NativeRead       | 2.7670161724091     | -                    | -
 use BigFileTools\BigFileTools;
 use BigFileTools\Driver;
 $bigFileTools = new BigFileTools(new Driver\CurlDriver());