我正在尝试加快视频文件的创建速度。我的问题是file_put_contents创建平均50mb视频文件花费的时间很长。我下面的代码将首先对视频进行解码,然后将其放入目录中。 $ Video 是一个字节数组。有没有一种方法可以在不进行base64解码的情况下创建视频文件,该怎么办才能加快文件创建速度?
document.querySelector('#load').addEventListener('click', function() {
var div = document.getElementById('demo');
var xhr = new XMLHttpRequest();
xhr.open("GET", "https://api.data.gov.sg/v1/transport/traffic-images", true);
xhr.onload = function() {
var response = JSON.parse(this.responseText);
response.items.forEach(function(item) {
item.cameras.forEach(function(camera) {
var img = document.createElement('img');
img.src = camera.image;
div.appendChild(img);
var p = document.createElement('p');
p.innerText = camera.location.latitude + ', ' + camera.location.longitude;
div.appendChild(p);
});
});
};
xhr.send();
});
答案 0 :(得分:1)
媒体文件可能很大,因此您无法使用将整个文件加载到RAM中的技术来处理它,更不用说同时拥有多个数据副本了。您的代码做了几次。
$json_str = file_get_contents('php://input');
$json_obj = json_decode($json_str);
$Video = $json_obj->Video;
$video_decode = base64_decode($Video);
这时,您已在RAM中加载了4个视频副本。对于50 MB的媒体文件,这意味着$video_decode
拥有50 MB的数据,而其他变量更大。您还需要累加json_decode()
之类的函数使用的内部存储器。要了解正在使用的RAM,可以在每个操作之间插入它:
var_dump(memory_get_usage(true));
此外,现代视频编解码器是高度优化的二进制流。如果将二进制数据转换为纯文本,则大小会增加。 Base64使数据增长4/3。 JSON会增加一些开销,尽管目前还不很严重。
如果必须从头开始设计,我将使用具有二进制格式(multipart/form-data
或自定义编码,可能只是文件原样)的POST request,然后只读取输入分块:
multipart/form-data
PHP does all the work。如果您希望或需要坚持当前的设计,则需要分块解决所有文件读取和解码操作:
base64_decode()
函数。最后但并非最不重要的一点是,永远不要通过注入不受信任的外部输入来创建SQL代码:
$sql = "UPDATE tblCaf SET Video = '$video_dbfilename' WHERE CAFNo = '$CAFNo'";
Use prepared statements instead。大量建议采用其他方法的教程应该早就被烧死了。
更新:似乎小块数据处理(相对于将所有内容加载到内存中)的概念并不像我想的那么简单,因此我将提供可运行的代码来说明差异
首先,让我们生成一个100 MB的文件进行测试:
$test = __DIR__ . '/test.txt';
$fp = fopen($test, 'wb') or die(1);
for ($i = 0; $i < 1839607; $i++) {
fwrite($fp, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n") or die(2);
}
fclose($fp);
如果您使用易于使用的一线助手功能:
ini_set('memory_limit', '300M');
$test = __DIR__ . '/test.txt';
printf("Current memory usage: %d MB\n", memory_get_usage(true) / 1024 / 1024);
$data = file_get_contents($test);
printf("Current memory usage: %d MB\n", memory_get_usage(true) / 1024 / 1024);
file_put_contents(__DIR__ . '/copy.txt', $data);
printf("Current memory usage: %d MB\n", memory_get_usage(true) / 1024 / 1024);
printf("Maximum memory usage: %d MB\n", memory_get_peak_usage(true) / 1024 / 1024);
...这是以需要大量内存(没有免费食物)为代价的:
Current memory usage: 0 MB
Current memory usage: 100 MB
Current memory usage: 100 MB
Maximum memory usage: 201 MB
如果将文件分成小块:
$test = __DIR__ . '/test.txt';
$chunk_size = 1024 * 1024;
$input = fopen($test, 'rb') or die(1);
$output = fopen(__DIR__ . '/copy.txt', 'wb') or die(2);
printf("Current memory usage: %d MB\n", memory_get_usage(true) / 1024 / 1024);
while (!feof($input)) {
$chunk = fread($input, $chunk_size) or die(3);
fwrite($output, $chunk) or die(4);
}
printf("Current memory usage: %d MB\n", memory_get_usage(true) / 1024 / 1024);
fclose($input);
fclose($output);
printf("Current memory usage: %d MB\n", memory_get_usage(true) / 1024 / 1024);
printf("Maximum memory usage: %d MB\n", memory_get_peak_usage(true) / 1024 / 1024);
...您可以为任何大小的文件使用固定数量的内存:
Current memory usage: 0 MB
Current memory usage: 1 MB
Current memory usage: 1 MB
Maximum memory usage: 3 MB