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

大QBW文件分片上传异常求助:类型为空、合并后0KB且格式错误

问题排查与修复方案

核心问题分析

1. 文件类型为空

QBW(QuickBooks文件)属于浏览器无法识别的小众格式,file.type会返回空字符串,这是浏览器的正常行为,需手动指定或通过扩展名推导。

2. 合并后文件异常(0KB/格式错误)

前端分片读取、传输逻辑错误,后端接收二进制数据的方式完全错误,导致实际未正确写入文件内容。


前端代码修复

关键修复点

  • 正确读取分片Blob:每次读取当前分片的blob而非整个文件
  • 用FormData传输二进制数据:避免jQuery自动编码破坏二进制内容
  • 修正分片切割范围:slice结束位置应为loadedSize + chunkSize,而非固定值
  • 手动指定QBW文件类型:浏览器无法识别该格式,直接设置为application/octet-stream

修改后的前端代码:

chunky: function(file, loadedSize) {
    const chunkSize = 1048576; // 1MB分片
    const totalFileSize = file.size;
    const noOfChunks = Math.ceil(totalFileSize / chunkSize);
    let reader = new FileReader();
    let requestNumber = loadedSize === 0 ? 1 : Math.floor(loadedSize / chunkSize) + 1;
    
    // 定义读取分片的方法
    function readNextChunk() {
        const start = (requestNumber - 1) * chunkSize;
        const end = Math.min(start + chunkSize, totalFileSize);
        const blob = file.slice(start, end);
        
        reader.readAsArrayBuffer(blob);
    }

    reader.onloadend = function(event) {
        if (event.target.readyState !== FileReader.DONE) return;
        if (!event.target.result) return;

        // 手动处理文件类型,QBW浏览器无法识别
        const fileType = file.type || 'application/octet-stream';
        
        // 用FormData封装二进制数据
        const formData = new FormData();
        formData.append('bloby', new Blob([event.target.result]), file.name);
        formData.append('fileName', file.name);
        formData.append('fileType', fileType);
        formData.append('fileSize', totalFileSize);
        formData.append('loadedSize', (requestNumber - 1) * chunkSize);
        formData.append('requestNumber', requestNumber);

        jQuery.ajax({
            url: IntegrationServer.path + '/uploadfileInChuncks?' + jQuery.param(Integration.addfile.requestParams),
            type: "POST",
            data: formData,
            processData: false, // 禁止jQuery处理数据
            contentType: false  // 让浏览器自动设置正确的Content-Type
        }).done(function(response) {
            console.log('分片上传完成:', response);
            const progress = Math.min(requestNumber / noOfChunks * 100, 100);
            jQuery('.upload_rpogress').html(`Uploaded: ${progress.toFixed(1)}%`);

            if (requestNumber < noOfChunks) {
                requestNumber++;
                readNextChunk();
            } else {
                console.log('所有分片上传完成,开始合并');
                jQuery('.upload_rpogress').html('Uploaded: 100%');
                Integration.addfile.mergeFile();
            }
        }).error(function(xhr, status, errorThrown) {
            jQuery('#errorMessage').html(xhr.responseText);
        });
    };

    // 启动第一个分片读取
    readNextChunk();
}

后端PHP代码修复

关键修复点

  • 正确接收二进制分片:通过$_FILES获取上传的文件内容,而非从getParams读取
  • 直接写入二进制数据:无需base64编码,避免额外编码导致文件损坏
  • 保留分片文件用于合并:不删除已存在的分片,确保每个分片独立存储

修改后的后端代码:

function uploadFileinChuncks($request, $response, $args) {
    try {
        // 获取上传的分片文件
        $chunkFile = $_FILES['bloby'] ?? null;
        if (!$chunkFile || $chunkFile['error'] !== UPLOAD_ERR_OK) {
            throw new Exception('分片文件上传失败');
        }

        $fileName = $_POST['fileName'] ?? '';
        $loadedSize = $_POST['loadedSize'] ?? 0;
        $requestNumber = $_POST['requestNumber'] ?? 0;
        $folderName = self::TEMP_FOLDER . self::QB_FOLDER;

        // 创建临时目录
        if (!is_dir($folderName)) {
            mkdir($folderName, 0777, true);
            chmod($folderName, 0777);
        }

        // 分片文件名:用序号+原文件名,确保顺序正确
        $destinationFile = $folderName . '/' . $requestNumber . '-' . $fileName;
        
        // 将上传的临时文件移动到目标位置
        if (!move_uploaded_file($chunkFile['tmp_name'], $destinationFile)) {
            throw new Exception('无法保存分片文件');
        }

        return $response->write($destinationFile);
    } catch (\Exception $e) {
        return $response->withStatus(500)->write($e->getMessage());
    }
}

合并文件补充逻辑

在mergeFile方法中需完成以下操作:

  1. 按分片序号从小到大排序所有分片文件
  2. 依次读取每个分片内容,写入最终QBW文件
  3. 删除所有临时分片文件

示例合并逻辑(PHP):

function mergeFile($fileName) {
    $folderName = self::TEMP_FOLDER . self::QB_FOLDER;
    $finalFile = self::UPLOAD_FOLDER . '/' . $fileName;
    
    // 获取所有分片文件并按序号排序
    $chunkFiles = glob($folderName . '/*-' . $fileName);
    usort($chunkFiles, function($a, $b) {
        $numA = explode('-', basename($a))[0];
        $numB = explode('-', basename($b))[0];
        return (int)$numA - (int)$numB;
    });

    // 合并文件
    $fp = fopen($finalFile, 'wb');
    foreach ($chunkFiles as $chunk) {
        fwrite($fp, file_get_contents($chunk));
        unlink($chunk); // 删除临时分片
    }
    fclose($fp);

    return $finalFile;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 12:54:25