PHP x86 comment obtenir la taille de fichier> 2 Go sans programme externe?

je dois obtenir la taille du fichier d'un fichier de plus de 2 Go de taille. (essai sur 4.6 GO de fichier). Est-il possible de faire cela sans un programme externe?

situation Actuelle:

  • filesize() , stat() et fseek() échoue
  • fread() et feof() works

il est possible d'obtenir la taille du fichier en lisant le contenu du fichier (extrêmement lent!).

$size = (float) 0;
$chunksize = 1024 * 1024;
while (!feof($fp)) {
    fread($fp, $chunksize);
    $size += (float) $chunksize;
}
return $size;

je sais comment l'obtenir sur des plates-formes 64 bits (en utilisant fseek($fp, 0, SEEK_END) et ftell() ), mais j'ai besoin de solution pour Plate-forme 32 bits.


Solution: j'ai commencé le projet open-source pour cela.

Gros Fichier "Outils De 1519290920"

Big File Tools est une collection de hacks qui sont nécessaires pour manipuler des fichiers de plus de 2 Go en PHP (même sur des systèmes 32 bits).

  • réponse: https://stackoverflow.com/a/35233556/631369
  • github: https://github.com/jkuchar/BigFileTools

24
demandé sur Community 2011-03-31 18:28:32

14 réponses

Voici une méthode possible:

il tente d'abord d'utiliser une commande shell appropriée à la plate-forme (modificateurs de substitution de shell Windows ou commande *nix/Mac stat ). Si cela échoue, il essaie COM (si on Windows), et retombe finalement sur filesize() .

/*
 * This software may be modified and distributed under the terms
 * of the MIT license.
 */

function filesize64($file)
{
    static $iswin;
    if (!isset($iswin)) {
        $iswin = (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN');
    }

    static $exec_works;
    if (!isset($exec_works)) {
        $exec_works = (function_exists('exec') && !ini_get('safe_mode') && @exec('echo EXEC') == 'EXEC');
    }

    // try a shell command
    if ($exec_works) {
        $cmd = ($iswin) ? "for %F in (\"$file\") do @echo %~zF" : "stat -c%s \"$file\"";
        @exec($cmd, $output);
        if (is_array($output) && ctype_digit($size = trim(implode("\n", $output)))) {
            return $size;
        }
    }

    // try the Windows COM interface
    if ($iswin && class_exists("COM")) {
        try {
            $fsobj = new COM('Scripting.FileSystemObject');
            $f = $fsobj->GetFile( realpath($file) );
            $size = $f->Size;
        } catch (Exception $e) {
            $size = null;
        }
        if (ctype_digit($size)) {
            return $size;
        }
    }

    // if all else fails
    return filesize($file);
}
21
répondu Unsigned 2018-04-11 17:20:21

j'ai commencé le projet Gros Fichier "Outils de 151980920" . Il est prouvé pour travailler sur Linux, Mac et Windows (même les variantes 32 bits). Il fournit des résultats byte-précis même pour les fichiers énormes (>4Go). À l'interne, il utilise brick/math - bibliothèque arithmétique de précision arbitraire.

Installer à l'aide de compositeur .

composer install jkuchar/BigFileTools

et l'utiliser:

<?php
$file = BigFileTools\BigFileTools::createDefault()->getFile(__FILE__);
echo $file->getSize() . " bytes\n";

résultat est BigInteger donc vous pouvez calculer avec des résultats

$sizeInBytes = $file->getSize();
$sizeInMegabytes = $sizeInBytes->toBigDecimal()->dividedBy(1024*1024, 2, \Brick\Math\RoundingMode::HALF_DOWN);    
echo "Size is $sizeInMegabytes megabytes\n";

Big File Tools internally utilise des pilotes pour déterminer de manière fiable la taille exacte des fichiers sur toutes les plateformes. Voici la liste des pilotes disponibles (mise à jour le 2016-02-05)

| 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     | -                    | -

vous pouvez utiliser BigFileTools avec l'un de ceux-ci ou le plus rapide disponible est choisi par défaut ( BigFileTools::createDefault() )

 use BigFileTools\BigFileTools;
 use BigFileTools\Driver;
 $bigFileTools = new BigFileTools(new Driver\CurlDriver());
5
répondu Honza Kuchař 2016-02-05 21:13:59
<?php
  ######################################################################
  # Human size for files smaller or bigger than 2 GB on 32 bit Systems #
  # size.php - 1.1 - 17.01.2012 - Alessandro Marinuzzi - www.alecos.it #
  ######################################################################
  function showsize($file) {
    if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {
      if (class_exists("COM")) {
        $fsobj = new COM('Scripting.FileSystemObject');
        $f = $fsobj->GetFile(realpath($file));
        $file = $f->Size;
      } else {
        $file = trim(exec("for %F in (\"" . $file . "\") do @echo %~zF"));
      }
    } elseif (PHP_OS == 'Darwin') {
      $file = trim(shell_exec("stat -f %z " . escapeshellarg($file)));
    } elseif ((PHP_OS == 'Linux') || (PHP_OS == 'FreeBSD') || (PHP_OS == 'Unix') || (PHP_OS == 'SunOS')) {
      $file = trim(shell_exec("stat -c%s " . escapeshellarg($file)));
    } else {
      $file = filesize($file);
    }
    if ($file < 1024) {
      echo $file . ' Byte';
    } elseif ($file < 1048576) {
      echo round($file / 1024, 2) . ' KB';
    } elseif ($file < 1073741824) {
      echo round($file / 1048576, 2) . ' MB';
    } elseif ($file < 1099511627776) {
      echo round($file / 1073741824, 2) . ' GB';
    } elseif ($file < 1125899906842624) {
      echo round($file / 1099511627776, 2) . ' TB';
    } elseif ($file < 1152921504606846976) {
      echo round($file / 1125899906842624, 2) . ' PB';
    } elseif ($file < 1180591620717411303424) {
      echo round($file / 1152921504606846976, 2) . ' EB';
    } elseif ($file < 1208925819614629174706176) {
      echo round($file / 1180591620717411303424, 2) . ' ZB';
    } else {
      echo round($file / 1208925819614629174706176, 2) . ' YB';
    }
  }
?>

utiliser comme suit:

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

et où vous voulez:

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

Si vous voulez l'améliorer, vous êtes les bienvenus!

4
répondu Alessandro Marinuzzi 2012-01-17 16:33:24

j'ai trouvé une bonne solution slim Pour Linux/Unix uniquement pour obtenir la taille de fichier de gros fichiers avec php 32 bits.

$file = "/path/to/my/file.tar.gz";
$filesize = exec("stat -c %s ".$file);

vous devez manipuler le $filesize comme chaîne de caractères. Essayer de lancer comme int donne un filesize = PHP_INT_MAX si le filesize est plus grand que PHP_INT_MAX.

mais bien que traitée comme chaîne de caractères, l'algo lisible par l'homme suivant fonctionne:

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)];
}

alors, ma sortie pour un fichier de plus de 4 Go:

4.46G
2
répondu steven 2015-03-27 08:40:10
$file_size=sprintf("%u",filesize($working_dir."\".$file));

cela fonctionne pour moi sur une boîte de fenêtres.

je regardais à travers le journal des bogues ici: https://bugs.php.net/bug.php?id=63618 et trouvé cette solution.

2
répondu Matt Smith 2015-12-31 05:40:47

si vous avez un serveur FTP, vous pouvez utiliser 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); 

(trouvé comme commentaire sur la ftp_size page)

0
répondu dave1010 2011-03-31 15:09:46

vous voudrez peut-être ajouter des alternatives à la fonction que vous utilisez, comme appeler les fonctions du système comme" dir " / " ls " et obtenir l'information à partir de là. Ils sont sujets à la sécurité bien sûr, des choses que vous pouvez vérifier et éventuellement revenir à la méthode lente en dernier recours seulement.

0
répondu Jorj 2011-03-31 15:18:36

une option serait de chercher à la marque de 2 Go et ensuite lire la longueur à partir de là...

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;
}

donc fondamentalement qui cherche à la plus grande positive integer signée représentable en PHP (2 Go pour un système de 32 bits), et lit ensuite en utilisant 8ko blocs (qui devrait être un compromis juste pour la meilleure efficacité de mémoire vs l'efficacité de transfert de disque).

notez aussi que je n'ajoute pas $chunksize à la taille. La raison en est que fread peut en fait renvoyer plus ou moins d'octets que $chunksize selon un certain nombre de possibilités. Ainsi, à la place, utilisez strlen pour déterminer la longueur de la chaîne parsée.

0
répondu ircmaxell 2011-03-31 18:50:45

quand IEEE double est utilisé (la plupart des systèmes), les tailles de fichier en dessous de ~4EB (etabytes = 10^18 octets) s'adaptent dans le double comme nombres précis (et il ne devrait pas y avoir de perte de précision lors de l'utilisation des opérations arithmétiques standard).

0
répondu kravčo 2011-04-01 14:16:49

vous ne pouvez pas obtenir de façon fiable la taille d'un fichier sur un système 32 bits en vérifiant si filesize() renvoie négatif, comme certaines réponses le suggèrent. C'est parce que si un fichier est entre 4 et 6 gigs sur un système de 32 bits filesize rapportera un nombre positif, puis négatif de 6 à 8 puis positif de 8 à 10 et ainsi de suite. Il fait une boucle, dans une manière de parler.

donc vous êtes bloqué en utilisant une commande externe qui fonctionne de manière fiable sur votre système 32 bits.

Cependant, un outil très utile est la possibilité de vérifier si la taille du fichier est supérieure à une certaine taille et vous pouvez le faire de manière fiable sur même les très gros fichiers.

cherche à 50 mégas et essaie de lire un octet. Il est très rapide sur ma machine de test low spec et fonctionne de manière fiable même lorsque la taille est beaucoup plus grande que 2 gigs.

vous pouvez l'utiliser pour vérifier si un fichier est supérieur à 2147483647 octets (2147483648 est Max int sur les systèmes 32 bits) et alors, manipulez le fichier différemment ou demandez à votre application d'émettre un avertissement.

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;
}
0
répondu Mark Maunder 2012-07-08 16:22:44

ci-dessous le code fonctionne bien pour n'importe quel fichier sur N'importe quelle version de PHP / OS / Webserver / plate-forme.

// 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
0
répondu WebAdmin at dekho-ji.com 2014-01-17 10:46:30

j'ai indiqué à de la BigFileTools classe/réponse:

- option pour désactiver la méthode curl car certaines plateformes (NAS de Synologie par exemple) ne prennent pas en charge le protocole FTP pour Curl

- extra non posix, mais plus précis, la mise en œuvre de sizeExec , au lieu de la taille sur le disque, le réel filesize est retourné en utilisant stat au lieu de du

- résultats de taille correcte pour les grands fichiers (>4 Go) et presque aussi rapide pour sizeNativeSeek

-les messages de débogage option

<?php

/**
 * Class for manipulating files bigger than 2GB
 * (currently supports only getting filesize)
 *
 * @author Honza Kuchař
 * @license New BSD
 * @encoding UTF-8
 * @copyright Copyright (c) 2013, Jan Kuchař
 */
class BigFileTools {

    /**
     * Absolute file path
     * @var string
     */
    protected $path;

    /**
     * Use in BigFileTools::$mathLib if you want to use BCMath for mathematical operations
     */
    const MATH_BCMATH = "BCMath";

    /**
     * Use in BigFileTools::$mathLib if you want to use GMP for mathematical operations
     */
    const MATH_GMP = "GMP";

    /**
     * Which mathematical library use for mathematical operations
     * @var string (on of constants BigFileTools::MATH_*)
     */
    public static $mathLib;

    /**
     * If none of fast modes is available to compute filesize, BigFileTools uses to compute size very slow
     * method - reading file from 0 byte to end. If you want to enable this behavior,
     * switch fastMode to false (default is true)
     * @var bool
     */
    public static $fastMode = true;

  //on some platforms like Synology NAS DS214+ DSM 5.1 FTP Protocol for curl is not working or disabled
  // you will get an error like "Protocol file not supported or disabled in libcurl"
    public static $FTPProtocolCurlEnabled = false; 
  public static $debug=false; //shows some debug/error messages
  public static $posix=true; //more portable but it shows size on disk not actual filesize so it's less accurate: 0..clustersize in bytes inaccuracy

    /**
     * Initialization of class
     * Do not call directly.
     */
    static function init() {
        if (function_exists("bcadd")) {
            self::$mathLib = self::MATH_BCMATH;
        } elseif (function_exists("gmp_add")) {
            self::$mathLib = self::MATH_GMP;
        } else {
            throw new BigFileToolsException("You have to install BCMath or GMP. There mathematical libraries are used for size computation.");
        }
    }

    /**
     * Create BigFileTools from $path
     * @param string $path
     * @return BigFileTools
     */
    static function fromPath($path) {
        return new self($path);
    }

    static function debug($msg) {
        if (self::$debug) echo $msg;
    }

    /**
     * Gets basename of file (example: for file.txt will return "file")
     * @return string
     */
    public function getBaseName() {
        return pathinfo($this->path, PATHINFO_BASENAME);
    }

    /**
     * Gets extension of file (example: for file.txt will return "txt")
     * @return string
     */
    public function getExtension() {
        return pathinfo($this->path, PATHINFO_EXTENSION);
    }


    /**
     * Gets extension of file (example: for file.txt will return "file.txt")
     * @return string
     */
    public function getFilename() {
        return pathinfo($this->path, PATHINFO_FILENAME);
    }

    /**
     * Gets path to file of file (example: for file.txt will return path to file.txt, e.g. /home/test/)
     * ! This will call absolute path!
     * @return string
     */
    public function getDirname() {
        return pathinfo($this->path, PATHINFO_DIRNAME);
    }

    /**
     * Gets md5 checksum of file content
     * @return string
     */
    public function getMd5() {
        return md5_file($this->path);
    }

    /**
     * Gets sha1 checksum of file content
     * @return string
     */
    public function getSha1() {
        return sha1_file($this->path);
    }

    /**
     * Constructor - do not call directly
     * @param string $path
     */
    function __construct($path, $absolutizePath = true) {
        if (!static::isReadableFile($path)) {
            throw new BigFileToolsException("File not found at $path");
        }

        if($absolutizePath) {
            $this->setPath($path);
        }else{
            $this->setAbsolutePath($path);
        }
    }

    /**
     * Tries to absolutize path and than updates instance state
     * @param string $path
     */
    function setPath($path) {

        $this->setAbsolutePath(static::absolutizePath($path));
    }

    /**
     * Setts absolute path
     * @param string $path
     */
    function setAbsolutePath($path) {
        $this->path = $path;
    }

    /**
     * Gets current filepath
     * @return string
     */
    function getPath($a = "") {
        if(a != "") {
            trigger_error("getPath with absolutizing argument is deprecated!", E_USER_DEPRECATED);
        }

        return $this->path;
    }

    /**
     * Converts relative path to absolute
     */
    static function absolutizePath($path) {

        $path = realpath($path);
        if(!$path) {
            // TODO: use hack like /q/replace-php-s-realpath-67041/"Not possible to resolve absolute path.");
        }
        return $path;
    }

    static function isReadableFile($file) {
        // Do not use is_file
        // @link https://bugs.php.net/bug.php?id=27792
        // $readable = is_readable($file); // does not always return correct value for directories

        $fp = @fopen($file, "r"); // must be file and must be readable
        if($fp) {
            fclose($fp);
            return true;
        }
        return false;
    }

    /**
     * Moves file to new location / rename
     * @param string $dest
     */
    function move($dest) {
        if (move_uploaded_file($this->path, $dest)) {
            $this->setPath($dest);
            return TRUE;
        } else {
            @unlink($dest); // needed in PHP < 5.3 & Windows; intentionally @
            if (rename($this->path, $dest)) {
                $this->setPath($dest);
                return TRUE;
            } else {
                if (copy($this->path, $dest)) {
                    unlink($this->path); // delete file
                    $this->setPath($dest);
                    return TRUE;
                }
                return FALSE;
            }
        }
    }

    /**
     * Changes path of this file object
     * @param string $dest
     */
    function relocate($dest) {
        trigger_error("Relocate is deprecated!", E_USER_DEPRECATED);
        $this->setPath($dest);
    }

    /**
     * Size of file
     *
     * Profiling results:
     *  sizeCurl        0.00045299530029297
     *  sizeNativeSeek  0.00052094459533691
     *  sizeCom         0.0031449794769287
     *  sizeExec        0.042937040328979
     *  sizeNativeRead  2.7670161724091
     *
     * @return string | float
     * @throws BigFileToolsException
     */
    public function getSize($float = false) {
        if ($float == true) {
            return (float) $this->getSize(false);
        }

        $return = $this->sizeCurl();
        if ($return) {
      $this->debug("sizeCurl succeeded");
            return $return;
        }
    $this->debug("sizeCurl failed");

        $return = $this->sizeNativeSeek();
        if ($return) {
      $this->debug("sizeNativeSeek succeeded");
            return $return;
        }
    $this->debug("sizeNativeSeek failed");

        $return = $this->sizeCom();
        if ($return) {
      $this->debug("sizeCom succeeded");
            return $return;
        }
    $this->debug("sizeCom failed");

        $return = $this->sizeExec();
        if ($return) {
      $this->debug("sizeExec succeeded");
            return $return;
        }
    $this->debug("sizeExec failed");

        if (!self::$fastMode) {
            $return = $this->sizeNativeRead();
            if ($return) {
        $this->debug("sizeNativeRead succeeded");
                return $return;
            }
      $this->debug("sizeNativeRead failed");
        }

        throw new BigFileToolsException("Can not size of file $this->path !");
    }

    // <editor-fold defaultstate="collapsed" desc="size* implementations">
    /**
     * Returns file size by using native fseek function
     * @see http://www.php.net/manual/en/function.filesize.php#79023
     * @see http://www.php.net/manual/en/function.filesize.php#102135
     * @return string | bool (false when fail)
     */
    protected function sizeNativeSeek() {
        $fp = fopen($this->path, "rb");
        if (!$fp) {
            return false;
        }

        flock($fp, LOCK_SH);
    $result= fseek($fp, 0, SEEK_END);

    if ($result===0) {
      if (PHP_INT_SIZE < 8) {
        // 32bit
        $return = 0.0;
        $step = 0x7FFFFFFF;
        while ($step > 0) {
          if (0 === fseek($fp, - $step, SEEK_CUR)) {
            $return += floatval($step);
          } else {
            $step >>= 1;
          }
        }
      }
      else { //64bit
        $return = ftell($fp);
      }
    }
    else $return = false;

    flock($fp, LOCK_UN);
    fclose($fp);
    return $return;
    }

    /**
     * Returns file size by using native fread function
     * @see /q/php-x86-how-to-get-filesize-of-2-gb-file-without-external-program-14215/"rb");
        if (!$fp) {
            return false;
        }
        flock($fp, LOCK_SH);

        rewind($fp);
        $offset = PHP_INT_MAX - 1;

        $size = (string) $offset;
        if (fseek($fp, $offset) !== 0) {
            flock($fp, LOCK_UN);
            fclose($fp);
            return false;
        }
        $chunksize = 1024 * 1024;
        while (!feof($fp)) {
            $read = strlen(fread($fp, $chunksize));
            if (self::$mathLib == self::MATH_BCMATH) {
                $size = bcadd($size, $read);
            } elseif (self::$mathLib == self::MATH_GMP) {
                $size = gmp_add($size, $read);
            } else {
                throw new BigFileToolsException("No mathematical library available");
            }
        }
        if (self::$mathLib == self::MATH_GMP) {
            $size = gmp_strval($size);
        }
        flock($fp, LOCK_UN);
        fclose($fp);
        return $size;
    }

    /**
     * Returns file size using curl module
     * @see http://www.php.net/manual/en/function.filesize.php#100434
     * @return string | bool (false when fail or cUrl module not available)
     */
    protected function sizeCurl() {
        // curl solution - cross platform and really cool :)
        if (self::$FTPProtocolCurlEnabled && function_exists("curl_init")) {
            $ch = curl_init("file://" . $this->path);
            curl_setopt($ch, CURLOPT_NOBODY, true);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_HEADER, true);
            $data = curl_exec($ch);
      if ($data=="" || empty($data)) $this->debug(stripslashes(curl_error($ch)));
            curl_close($ch);
            if ($data !== false && preg_match('/Content-Length: (\d+)/', $data, $matches)) {
                return (string) $matches[1];
            }
        } else {
            return false;
        }
    }

    /**
     * Returns file size by using external program (exec needed)
     * @see /q/php-x86-how-to-get-filesize-of-2-gb-file-without-external-program-14215/"exec")) {

            if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') { // Windows
                // Try using the NT substition modifier %~z
        $escapedPath = escapeshellarg($this->path);
                $size = trim(exec("for %F in ($escapedPath) do @echo %~zF"));
            }else{ // other OS
                // If the platform is not Windows, use the stat command (should work for *nix and MacOS)
        if (self::$posix) {
          $tmpsize=trim(exec("du \"".$this->path."\" | cut -f1")); 
          //du returns blocks/KB
          $size=(int)$tmpsize*1024; //make it bytes
        }
        else $size=trim(exec('stat "'.$this->path.'" | grep -i -o -E "Size: ([0-9]+)" | cut -d" " -f2'));

        if (self::$debug) var_dump($size);
        return $size;
            }

        }
        return false;
    }

    /**
     * Returns file size by using Windows COM interface
     * @see /q/php-x86-how-to-get-filesize-of-2-gb-file-without-external-program-14215/"COM")) {
            // Use the Windows COM interface
            $fsobj = new COM('Scripting.FileSystemObject');
            if (dirname($this->path) == '.')
                $this->path = ((substr(getcwd(), -1) == DIRECTORY_SEPARATOR) ? getcwd() . basename($this->path) : getcwd() . DIRECTORY_SEPARATOR . basename($this->path));
            $f = $fsobj->GetFile($this->path);
            return (string) $f->Size;
        }
    }

    // </editor-fold>
}

BigFileTools::init();

class BigFileToolsException extends Exception{}
0
répondu Jan 2015-08-15 21:34:50

la façon la plus facile de faire cela serait simplement d'ajouter une valeur max à votre nombre. Cela signifie que sur la plate-forme x86 le nombre Long ajoute 2^32:

if($size < 0) $size = pow(2,32) + $size;

exemple: Big_File.exe-3,30 Gb (3.554.287.616 b) Votre fonction retourne -740679680 donc vous ajoutez 2^32 (4294967296) et obtenez 3554287616.

vous obtenez le nombre négatif parce que votre système réserve un peu de mémoire au signe négatif, de sorte que vous êtes laissé avec 2^31 (2.147.483.648 = 2G) valeur maximale de soit négatif ou positif. Lorsque le système atteint cette valeur maximale, il ne s'arrête pas, mais écrase simplement le dernier bit réservé et votre nombre est maintenant forcé à négatif. En termes plus simples, quand vous dépassez le nombre positif maximum, vous serez forcé au nombre négatif maximum, donc 2147483648 + 1 = -2147483648. Une autre addition va vers zéro et de nouveau vers le nombre maximum.

comme vous pouvez le voir c'est comme un cercle avec les nombres les plus élevés et les plus bas fermant la boucle.

nombre total maximum que l'architecture x86 peut "digérer" en une seule touche est 2^32 = 4294967296 = 4G, aussi longtemps que votre nombre est inférieur à cela, cette astuce simple fonctionnera toujours. Dans les nombres supérieurs vous devez savoir combien de fois vous avez dépassé le point de boucle et simplement le multiplier par 2^32 et l'ajouter à votre résultat:

$size = pow(2,32) * $loops_count + $size;

bien sûr, dans la base des fonctions PHP c'est assez difficile à faire, car aucune fonction va vous dire combien de fois il a passé le point de boucle, de sorte que cela ne fonctionnera pas pour les fichiers plus de 4Gigs.

0
répondu Šarūnas Sirotka 2016-01-09 18:52:49

j'ai écrit une fonction qui retourne la taille du fichier exactement et est assez rapide:

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;
}
-1
répondu K. Biermann 2013-07-24 22:49:47