PHP读取大文件教程 // formatBytes 方法取材于 php.net 文档
memory_get_peak_usage();
function formatBytes($bytes, $precision = 2) {
$units = array("b", "kb", "mb", "gb", "tb");
$bytes = max($bytes, 0);
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
$pow = min($pow, count($units) - 1);
$bytes /= (1 << (10 * $pow));
return round($bytes, $precision) . " " . $units[$pow];
}我们有什么选择? 逐行读取文件 // from memory.php
function formatBytes($bytes, $precision = 2) {
$units = array("b", "kb", "mb", "gb", "tb");
$bytes = max($bytes, 0);
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
$pow = min($pow, count($units) - 1);
$bytes /= (1 << (10 * $pow));
return round($bytes, $precision) . " " . $units[$pow];
}
print formatBytes(memory_get_peak_usage());
// from reading-files-line-by-line-1.php
function readTheFile($path) {
$lines = [];
$handle = fopen($path, "r");
while(!feof($handle)) {
$lines[] = trim(fgets($handle));
}
fclose($handle);
return $lines;
}
readTheFile("shakespeare.txt");
require "memory.php";// from reading-files-line-by-line-2.php
function readTheFile($path) {
$handle = fopen($path, "r");
while(!feof($handle)) {
yield trim(fgets($handle));
}
fclose($handle);
}
readTheFile("shakespeare.txt");
require "memory.php";// from reading-files-line-by-line-3.php
$iterator = readTheFile("shakespeare.txt");
$buffer = "";
foreach ($iterator as $iteration) {
preg_match("/\n{3}/", $buffer, $matches);
if (count($matches)) {
print ".";
$buffer = "";
} else {
$buffer .= $iteration . PHP_EOL;
}
}
require "memory.php";文件之间的管道 // from piping-files-1.php
file_put_contents(
"piping-files-1.txt", file_get_contents("shakespeare.txt")
);
require "memory.php";// from piping-files-2.php
$handle1 = fopen("shakespeare.txt", "r");
$handle2 = fopen("piping-files-2.txt", "w");
stream_copy_to_stream($handle1, $handle2);
fclose($handle1);
fclose($handle2);
require "memory.php";// from piping-files-3.php
file_put_contents(
"piping-files-3.jpeg", file_get_contents(
"https://github测试数据/assertchris/uploads/raw/master/rick.jpg"
)
);
// ...or write this straight to stdout, if we don't need the memory info
require "memory.php";
逐行读取文件 // from memory.php
function formatBytes($bytes, $precision = 2) {
$units = array("b", "kb", "mb", "gb", "tb");
$bytes = max($bytes, 0);
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
$pow = min($pow, count($units) - 1);
$bytes /= (1 << (10 * $pow));
return round($bytes, $precision) . " " . $units[$pow];
}
print formatBytes(memory_get_peak_usage());
// from reading-files-line-by-line-1.php
function readTheFile($path) {
$lines = [];
$handle = fopen($path, "r");
while(!feof($handle)) {
$lines[] = trim(fgets($handle));
}
fclose($handle);
return $lines;
}
readTheFile("shakespeare.txt");
require "memory.php";// from reading-files-line-by-line-2.php
function readTheFile($path) {
$handle = fopen($path, "r");
while(!feof($handle)) {
yield trim(fgets($handle));
}
fclose($handle);
}
readTheFile("shakespeare.txt");
require "memory.php";// from reading-files-line-by-line-3.php
$iterator = readTheFile("shakespeare.txt");
$buffer = "";
foreach ($iterator as $iteration) {
preg_match("/\n{3}/", $buffer, $matches);
if (count($matches)) {
print ".";
$buffer = "";
} else {
$buffer .= $iteration . PHP_EOL;
}
}
require "memory.php";文件之间的管道 // from piping-files-1.php
file_put_contents(
"piping-files-1.txt", file_get_contents("shakespeare.txt")
);
require "memory.php";// from piping-files-2.php
$handle1 = fopen("shakespeare.txt", "r");
$handle2 = fopen("piping-files-2.txt", "w");
stream_copy_to_stream($handle1, $handle2);
fclose($handle1);
fclose($handle2);
require "memory.php";// from piping-files-3.php
file_put_contents(
"piping-files-3.jpeg", file_get_contents(
"https://github测试数据/assertchris/uploads/raw/master/rick.jpg"
)
);
// ...or write this straight to stdout, if we don't need the memory info
require "memory.php";
// from piping-files-1.php
file_put_contents(
"piping-files-1.txt", file_get_contents("shakespeare.txt")
);
require "memory.php";// from piping-files-2.php
$handle1 = fopen("shakespeare.txt", "r");
$handle2 = fopen("piping-files-2.txt", "w");
stream_copy_to_stream($handle1, $handle2);
fclose($handle1);
fclose($handle2);
require "memory.php";// from piping-files-3.php file_put_contents( "piping-files-3.jpeg", file_get_contents( "https://github测试数据/assertchris/uploads/raw/master/rick.jpg" ) ); // ...or write this straight to stdout, if we don't need the memory info require "memory.php";
内存使用情况为 581KB,现在,我们如何尝试进行流传输呢?
// from piping-files-4.php $handle1 = fopen( "https://github测试数据/assertchris/uploads/raw/master/rick.jpg", "r" ); $handle2 = fopen( "piping-files-4.jpeg", "w" ); // ...or write this straight to stdout, if we don't need the memory info stream_copy_to_stream($handle1, $handle2); fclose($handle1); fclose($handle2); require "memory.php";
内存使用比刚才略少 (400 KB),但是结果是相同的。如果我们不需要内存信息,也可以打印至标准输出。PHP 提供了一种简单的方法来执行此操作:
$handle1 = fopen( "https://github测试数据/assertchris/uploads/raw/master/rick.jpg", "r" ); $handle2 = fopen( "php://stdout", "w" ); stream_copy_to_stream($handle1, $handle2); fclose($handle1); fclose($handle2); // require "memory.php"; 其他流 还存在一些流可以通过管道来读写。 php://stdin只读 php://stderr只写,与php://stdout相似 php://input只读,使我们可以访问原始请求内容 php://output只写,可让我们写入输出缓冲区
过滤器 // from filters-1.php
$zip = new ZipArchive();
$filename = "filters-1.zip";
$zip->open($filename, ZipArchive::CREATE);
$zip->addFromString("shakespeare.txt", file_get_contents("shakespeare.txt"));
$zip->close();
require "memory.php";
这段代码虽然整洁,但是总共使用了大概 10.75 MB 的内存。我们可以使用过滤器来进行优化
// from filters-2.php $handle1 = fopen( "php://filter/zlib.deflate/resource=shakespeare.txt", "r" ); $handle2 = fopen( "filters-2.deflated", "w" ); stream_copy_to_stream($handle1, $handle2); fclose($handle1); fclose($handle2); require "memory.php";
// from filters-2.php file_get_contents( "php://filter/zlib.inflate/resource=filters-2.deflated" );
// from creating-contexts-1.php
$data = join("&", [
"twitter=assertchris",
]);
$headers = join("\r\n", [
"Content-type: application/x-www-form-urlencoded",
"Content-length: " . strlen($data),
]);
$options = [
"http" => [
"method" => "POST",
"header"=> $headers,
"content" => $data,
],
];
$context = stream_content_create($options);
$handle = fopen("https://example测试数据/register", "r", false, $context);
$response = stream_get_contents($handle);
fclose($handle);创建自定义协议和过滤器
在总结之前,我们先谈谈创建自定义协议。
Protocol {
public resource $context;
public __construct ( void )
public __destruct ( void )
public bool dir_closedir ( void )
public bool dir_opendir ( string $path , int $options )
public string dir_readdir ( void )
public bool dir_rewinddir ( void )
public bool mkdir ( string $path , int $mode , int $options )
public bool rename ( string $path_from , string $path_to )
public bool rmdir ( string $path , int $options )
public resource stream_cast ( int $cast_as )
public void stream_close ( void )
public bool stream_eof ( void )
public bool stream_flush ( void )
public bool stream_lock ( int $operation )
public bool stream_metadata ( string $path , int $option , mixed $value )
public bool stream_open ( string $path , string $mode , int $options ,
string &$opened_path )
public string stream_read ( int $count )
public bool stream_seek ( int $offset , int $whence = SEEK_SET )
public bool stream_set_option ( int $option , int $arg1 , int $arg2 )
public array stream_stat ( void )
public int stream_tell ( void )
public bool stream_truncate ( int $new_size )
public int stream_write ( string $data )
public bool unlink ( string $path )
public array url_stat ( string $path , int $flags )
}if (in_array("highlight-names", stream_get_wrappers())) {
stream_wrapper_unregister("highlight-names");
}
stream_wrapper_register("highlight-names", "HighlightNamesProtocol");
$highlighted = file_get_contents("highlight-names://story.txt");Filter {
public $filtername;
public $params
public int filter ( resource $in , resource $out , int &$consumed ,
bool $closing )
public void onClose ( void )
public bool onCreate ( void )
}可被轻松注册 $handle = fopen("story.txt", "w+");
stream_filter_append($handle, "highlight-names", STREAM_FILTER_READ);总结
声明:本文来自网络,不代表【好得很程序员自学网】立场,转载请注明出处:http://www.haodehen.cn/did27767