1

我正在使用 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 流式传输文件名似乎也不起作用。

4

1 回答 1

2

您遇到的问题与此有关。

fread($handle,filesize($my_file));

有了里面的文件大小,你还不如做file_get_contents. 一次读取 1 行在记忆方面要好得多fget

$handle = fopen($myfile, 'r');

while(!feof($handle)){
     $line = fgets($handle);
} 

这样您只需将一行读入内存,但如果您需要完整的文件内容,您仍然会遇到瓶颈。

唯一真正的方法是流式上传。

我做了一个快速搜索,如果你给它文件名,似乎 CURL 的默认值是流式传输文件

 $post_data['file'] = 'myfile.csv';

 curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);

您可以查看上一个答案以获取更多详细信息

是否可以使用 cURL 通过 POST 流式上传文件?

所以只要你能通过sha1_file它看起来你可以只流式传输文件,这应该避免内存问题。不过可能有时间限制的问题。此外,如果失败,我真的想不出解决方法。

仅供参考,我个人从未尝试过,通常我只是使用 sFTP 进行大文件传输。所以我不知道它是否必须是特别post_data['file'] 的,我只是从另一个答案中复制了它。

祝你好运...

更新

看到流媒体似乎失败了(见评论)。

您可能需要测试流式传输以确保其正常工作。我不知道这会涉及什么,也许将文件流式传输到您自己的服务器?此外,我不确定为什么它不能“像宣传的那样”工作,您可能已经对其进行了测试。但是测试一些东西永远不会有坏处,在你确定之前永远不要假设某些东西有效。尝试一些新的解决方案很容易,只是错过了一个设置或把路径弄错了,然后又回到原来的问题上去思考它。

我花了很多时间把东西拆开才意识到我有一个拼写错误。这些天我非常擅长编程,所以我通常也会过度思考错误。我的观点是,在继续之前确保这不是一个简单的错误。

假设一切设置正确,我会尝试file_get_contents. 我不知道它是否会更好,但它更适合打开整个文件。它在代码中似乎也更具可读性,因为很明显需要整个文件。如果没有别的,它似乎在语义上更正确。

您还可以通过使用增加 PHP 可以访问的 RAM

ini_set('memory_limit', '512M')

你甚至可以更高,这取决于你的服务器。我之前去的最高的是3G,但是我使用的服务器有54GBram,这是一次性的,(我们将 1.3 亿行从 MySql 迁移到 MongoDB,innodb 索引占用了 30+GB )。通常我会运行512M并拥有一些经常需要的脚本1G。但我不会随便增加内存。在优化和测试之后,这通常是我最后的手段。我们做了很多繁重的处理,这就是为什么我们有这么大的服务器,我们还有 2 个从属服务器(除其他外),每个运行 16GB。

至于要放置的大小,通常我会通过128M告诉它有效来增加它,然后添加一个额外128M的以确保,但您可能希望以更小的步骤进行。通常人们总是使用 8 的倍数,但我不知道这些天这是否有很大的不同。

再次,祝你好运。

于 2018-04-05T09:44:16.860 回答