PHP x86如何获取>;的文件大小;没有外部程序的2GB文件?
我需要得到一个文件大小超过2GB的文件。(在4.6 GB文件上进行测试)。在没有外部程序的情况下,有没有办法做到这一点 当前状态: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的文件(甚
,filesize()
和stat()
失败fseek()
和fread()
有效feof()
fseek($fp,0,SEEK_END)
和ftell()
),但我需要32位平台的解决方案
解决方案:我已经为此启动了开源项目 大文件工具 大文件工具是在PHP中操作超过2GB的文件(甚至在32位系统上)所需的黑客的集合
- 答复:
- github:
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());