You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用fread读取大文件致内存不足,求Backblaze B2上传优化方案

嘿,我完全懂你的痛点——一次性把大文件塞进内存简直是内存杀手!其实Backblaze B2专门提供了大文件分块上传的机制,完美解决这个问题,不用把整个文件加载到内存里。咱们一步步来拆解怎么做:

为什么原来的代码会出问题?

你原来的代码用fread($handle, filesize($my_file))直接把整个文件读进内存,当文件超过PHP的内存限制(通常默认是128MB)时,必然会触发内存不足的错误。

解决方案:B2大文件分块上传

B2允许将大文件拆分成多个至少5MB的块(建议用100MB,刚好避开你的问题阈值),逐个上传这些块,最后再把它们合并成完整文件。这样每次只需要在内存里保留一个块的数据,内存占用就可控了。

步骤1:准备基础配置

首先确保你已经获取了B2的API授权信息(accountId、applicationKey、bucketId这些),然后初始化必要的API请求。

步骤2:手动实现分块上传代码

这里给你一个底层实现的示例(如果用官方SDK会更简单,后面会提):

<?php
$file_name = "file.txt";
$my_file = "<path-to-file>" . $file_name;
$chunkSize = 100 * 1024 * 1024; // 100MB 每块
$fileHandle = fopen($my_file, 'rb');
$fileSize = filesize($my_file);

// 1. 启动大文件上传
$startLargeFileUrl = "https://api.backblazeb2.com/b2api/v2/b2_start_large_file";
$startPayload = json_encode([
    "bucketId" => "YOUR_BUCKET_ID",
    "fileName" => $file_name,
    "contentType" => "text/plain" // 根据你的文件类型调整
]);

// 发送请求(替换成你的授权令牌)
$startResponse = sendB2Request($startLargeFileUrl, $startPayload);
$fileId = $startResponse->fileId;

// 2. 分块读取并上传
$chunkIndex = 0;
$sha1List = [];
while (!feof($fileHandle)) {
    $chunk = fread($fileHandle, $chunkSize);
    if (empty($chunk)) break;
    
    // 计算当前块的SHA1哈希(B2要求上传块时提供)
    $chunkSha1Hex = bin2hex(sha1($chunk, true));
    $sha1List[] = $chunkSha1Hex;
    
    // 获取当前块的上传URL
    $getUploadPartUrl = "https://api.backblazeb2.com/b2api/v2/b2_get_upload_part_url";
    $getPartPayload = json_encode(["fileId" => $fileId]);
    $partUrlResponse = sendB2Request($getUploadPartUrl, $getPartPayload);
    $uploadUrl = $partUrlResponse->uploadUrl;
    $authorizationToken = $partUrlResponse->authorizationToken;
    
    // 上传当前块
    $uploadHeaders = [
        "Authorization: $authorizationToken",
        "Content-Type: application/octet-stream",
        "X-Bz-Part-Number: " . ($chunkIndex + 1),
        "X-Bz-Content-Sha1: $chunkSha1Hex"
    ];
    
    $uploadResponse = sendB2UploadRequest($uploadUrl, $chunk, $uploadHeaders);
    $chunkIndex++;
}

fclose($fileHandle);

// 3. 完成大文件上传
$finishLargeFileUrl = "https://api.backblazeb2.com/b2api/v2/b2_finish_large_file";
$finishPayload = json_encode([
    "fileId" => $fileId,
    "partSha1Array" => $sha1List
]);
$finishResponse = sendB2Request($finishLargeFileUrl, $finishPayload);

// 辅助函数:发送B2 JSON API请求
function sendB2Request($url, $payload) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        "Authorization: YOUR_AUTH_TOKEN", // 替换成你的授权令牌
        "Content-Type: application/json"
    ]);
    $response = curl_exec($ch);
    curl_close($ch);
    return json_decode($response);
}

// 辅助函数:发送块上传请求(二进制数据)
function sendB2UploadRequest($url, $data, $headers) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    $response = curl_exec($ch);
    curl_close($ch);
    return json_decode($response);
}
?>

更省心的方式:使用官方PHP SDK

如果你不想自己写这么多底层代码,Backblaze官方有PHP SDK,已经内置了大文件分块上传的功能,一行代码就能搞定,而且自动处理内存管理:

<?php
use BackblazeB2\BackblazeB2;

$b2 = new BackblazeB2([
    'accountId' => 'YOUR_ACCOUNT_ID',
    'applicationKey' => 'YOUR_APPLICATION_KEY',
]);

$b2->uploadLargeFile([
    'bucketId' => 'YOUR_BUCKET_ID',
    'fileName' => $file_name,
    'filePath' => $my_file,
    'partSize' => 100 * 1024 * 1024 // 100MB每块
]);
?>

这个SDK会自动分块读取文件,每次只加载一个块到内存,完全不用你手动处理分块、哈希计算和API请求,非常省心。

额外注意事项

  • 确保你的PHP内存限制至少能容纳一个块的大小(比如100MB的话,内存限制设为128MB就够了)
  • 每个块的大小必须至少5MB,B2不接受更小的块
  • 上传过程中如果某个块失败,可以单独重新上传这个块,不用重新传整个文件
  • 记得处理API请求的错误情况(比如网络中断、授权失败等)

内容的提问来源于stack exchange,提问作者Rohan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 08:04:49