我正在使用Backblaze B2存储文件,并使用他们的文档代码通过他们的API上传。但是,他们的代码使用fread来读取文件,这会导致大于100MB的文件出现问题,因为它会尝试将整个文件加载到内存中。有没有更好的方法可以将整个文件加载到RAM中?
$file_name = "file.txt";
$my_file = "<path-to-file>" . $file_name;
$handle = fopen($my_file, 'r');
$read_file = fread($handle,filesize($my_file));
$upload_url = ""; // Provided by b2_get_upload_url
$upload_auth_token = ""; // Provided by b2_get_upload_url
$bucket_id = ""; // The ID of the bucket
$content_type = "text/plain";
$sha1_of_file_data = sha1_file($my_file);
$session = curl_init($upload_url);
// Add read file as post field
curl_setopt($session, CURLOPT_POSTFIELDS, $read_file);
// Add headers
$headers = array();
$headers[] = "Authorization: " . $upload_auth_token;
$headers[] = "X-Bz-File-Name: " . $file_name;
$headers[] = "Content-Type: " . $content_type;
$headers[] = "X-Bz-Content-Sha1: " . $sha1_of_file_data;
curl_setopt($session, CURLOPT_HTTPHEADER, $headers);
curl_setopt($session, CURLOPT_POST, true); // HTTP POST
curl_setopt($session, CURLOPT_RETURNTRANSFER, true); // Receive server response
$server_output = curl_exec($session); // Let's do this!
curl_close ($session); // Clean up
echo ($server_output); // Tell me about the rabbits, George!
我尝试过使用:
curl_setopt($session, CURLOPT_POSTFIELDS, array('file' => '@'.realpath('file.txt')));
但是我收到错误响应:读取上传数据时出错:SocketTimeoutException(读取超时)
编辑:使用CURL流式传输文件名似乎也不起作用。
答案 0 :(得分:2)
您遇到的问题与此有关。
fread($handle,filesize($my_file));
使用文件大小,你可以做file_get_contents
。使用fget
$handle = fopen($myfile, 'r');
while(!feof($handle)){
$line = fgets($handle);
}
这样你只需要在内存中读取一行,但如果你需要完整的文件内容,你仍然会遇到瓶颈。
唯一真正的方法是流式上传。
我做了一个快速搜索,似乎CURL的默认设置是流式文件,如果你给它文件名
$post_data['file'] = 'myfile.csv';
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
您可以查看上一个答案以获取更多详细信息
Is it possible to use cURL to stream upload a file using POST?
所以只要你能超越sha1_file
看起来你可以只传输文件,这应该避免内存问题。但是可能存在时间限制问题。如果失败,我也无法想到获取哈希的方法。
仅供参考,我个人从未尝试过,通常我只是使用sFTP进行大型文件传输。所以我不知道是否必须特别post_data['file']
我只是从另一个答案中复制了它。
<强>更新强>
看到流媒体似乎失败了(见评论)。
您可能需要测试流式传输以确保其正常运行。我不知道会涉及到什么,可能会将文件流式传输到您自己的服务器?此外,我不确定为什么它不会像“广告宣传”一样工作,你可能已经测试过了。但是,测试某些东西永远不会伤害,在你确定之前永远不要假设有些东西可行。尝试新的解决方案很容易,只是错过设置或错误的路径,然后根据原始问题回过头来思考它。
我花了很多时间把事情分开才意识到我有拼写错误。这些天我非常擅长编程,所以我通常也会忽略这些错误。我的观点是,在继续前进之前,请确保这不是一个简单的错误。
假设一切设置正确,我会尝试file_get_contents
。我不知道它会不会更好但是更多的意思是打开整个文件。它在代码中似乎也更易读,因为很明显需要整个文件。如果没别的话,它似乎在语义上更正确。
您还可以使用
增加PHP可以访问的RAMini_set('memory_limit', '512M')
根据您的服务器,您甚至可以更高。之前我去过的最高点是3G
,但我使用的服务器有54GB
ram,这是一次性的事情(我们从MySql向MongoDB迁移了1.3亿行,innodb索引正在吃掉30 + GB)。通常,我使用512M
运行,并且有一些常规需要1G
的脚本。但是,我不会毫不犹豫地追寻记忆。在优化和测试之后,这通常是我的最后手段。我们做了很多繁重的处理,这就是为什么我们有这么大的服务器,我们还有2个奴隶服务器(除此之外),每个服务器运行16GB。
至于要放置的大小,通常我会将其增加128M
告诉它有效,然后添加额外的128M
以确保,但您可能希望采用较小的步骤。通常人们总是使用8的倍数,但我不知道这些日子是否会产生很大差异。
再次,祝你好运。