PHP x86 Как получить размер файла & gt; Файл 2 Гб без внешней программы?

Мне нужно получить размер файла более 2 ГБ. (тестирование на 4,6 ГБ файла). Есть ли способ сделать это без внешней программы?

Текущее состояние:

  • filesize(), stat() а также fseek() терпит неудачу
  • fread() а также feof() работает

Существует возможность получить размер файла путем чтения содержимого файла (очень медленно!).

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

Я знаю, как получить его на 64-битных платформах (используя fseek($fp, 0, SEEK_END) а также ftell()), но мне нужно решение для 32-битной платформы.


Решение: Я начал проект с открытым исходным кодом для этого.

Инструменты для работы с большими файлами

Big File Tools — это набор хаков, которые необходимы для манипулирования файлами размером более 2 ГБ в PHP (даже в 32-битных системах).

24

Решение

Вот один из возможных методов:

Сначала он пытается использовать подходящую для платформы команду оболочки (модификаторы подстановки оболочки Windows или * nix / Mac stat команда). Если это не удается, он пытается COM (если на Windows), и, наконец, возвращается к 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

Другие решения

Я начал проект под названием Инструменты для работы с большими файлами. это доказанный работать на Linux, Mac и Windows (даже 32-битных вариантах). Он обеспечивает точные байтовые результаты даже для больших файлов (> 4 ГБ). Внутренне он использует кирпич / математика — арифметическая библиотека произвольной точности.

Установите его, используя композитор.

composer install jkuchar/BigFileTools

и использовать это:

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

Result — BigInteger, поэтому вы можете вычислять результаты

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

Big File Tools внутренне использует драйверы для надежного определения точного размера файла на всех платформах. Вот список доступных драйверов (обновлено 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     | -                    | -

Вы можете использовать BigFileTools с любым из них или по умолчанию выбран самый быстрый из доступных (BigFileTools::createDefault())

 use BigFileTools\BigFileTools;
use BigFileTools\Driver;
$bigFileTools = new BigFileTools(new Driver\CurlDriver());
5

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

Используйте как следовать:

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

И где вы хотите:

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

Если вы хотите улучшить его, пожалуйста!

4

Я нашел хорошее тонкое решение для Linux / Unix только для получения файлов большого размера с 32-битным php.

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

Вы должны обращаться с $filesize как строка Попытка приведения к типу int приводит к увеличению размера файла = PHP_INT_MAX, если размер файла больше, чем 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 Гб:

4.46G
2
$file_size=sprintf("%u",filesize($working_dir."\\".$file));

Это работает для меня на Windows Box.

Я просматривал журнал ошибок здесь: https://bugs.php.net/bug.php?id=63618 и нашел это решение.

2

Если у вас есть 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);

(Найдено в качестве комментария к ftp_size страница)

0

вы можете захотеть добавить некоторые альтернативы к используемой вами функции, такие как вызов системных функций, таких как «dir» / «ls», и получить информацию оттуда. Конечно, они являются предметом безопасности, вещи, которые вы можете проверить и в конечном итоге вернуться к медленному методу только в качестве крайней меры.

0

Одним из вариантов будет поиск до отметки 2 ГБ, а затем прочитать длину оттуда …

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

Так что, в основном, он ищет наибольшее целое число с положительным знаком, представимое в PHP (2 ГБ для 32-битной системы), а затем читает с использованием блоков по 8 КБ (что должно быть справедливым компромиссом для лучшей эффективности памяти по сравнению с эффективностью передачи диска).

Также обратите внимание, что я не добавляю $chunksize по размеру. Причина в том, что fread может на самом деле вернуть больше или меньше байтов, чем $chunksize в зависимости от ряда возможностей. Так что вместо этого используйте strlen определить длину анализируемой строки.

0
По вопросам рекламы [email protected]