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

使用DevExtreme dxFileManager分片上传文件遇异常求助

问题分析与修复方案

问题原因拆解

1. 临时文件夹出现多个原文件大小的文件

前端未配置chunkSize参数,导致dxFileManager没有对文件进行真正分片,而是重复上传完整文件,每个"分片"都是原文件的完整副本,最终生成大量同大小临时文件。

2. 上传完成后临时文件未删除

后端仅在最后一个分片到达时删除当前分片的临时文件,未处理同一文件的其他分片;同时因之前的重复上传问题,大量冗余临时文件未被清理。


修复步骤

第一步:前端添加分片配置

在dxFileManager的配置中加入upload选项,指定分片大小(示例为200KB,可按需调整):

$('#md_DocumentiServizio').dxFileManager({
    name: 'fileManager',
    // 新增分片上传配置
    upload: {
        chunkSize: 200 * 1024 // 200KB/分片
    },
    fileSystemProvider: new DevExpress.fileManagement.CustomFileSystemProvider({ 
        getItems: function(pathInfo) { 
            return $.ajax({
                url: "./include/gestione_servizio/documenti/getDocumenti.php",
                method: "GET",
                data: {
                    Lingua: lingua_attiva,
                    IdSped: dati_testata.trkbid,
                    selPath: pathInfo.path
                },
                dataType: "json"
            })
        },
        downloadItems: function(items) {                
            items.forEach(function (item, index) {
                const jsonData = JSON.stringify(item);
                $.ajax({
                    url: "./include/gestione_servizio/documenti/saveDocumenti.php",
                    method: "POST",
                    data: jsonData,
                    xhrFields: {
                        responseType: "blob"
                    },
                    success: function(data) {
                        const filename = item.name;
                        const file = new File([data], filename, {type: data.type});
                        saveAs(file);
                    }
                });
            });
        },              
        uploadFileChunk: function(fileData, uploadInfo, destinationDirectory) {             
            console.log(uploadInfo);
            const formData = new FormData();
            formData.append('file', fileData);
            formData.append('uploadInfo', JSON.stringify(uploadInfo));
            formData.append('destinationDirectory', JSON.stringify(destinationDirectory));

            return $.ajax({
                url: "./include/gestione_servizio/documenti/uploadDocumenti.php",
                method: "POST",
                data: formData,
                processData: false,
                contentType: false
            });
        }
    }),
    height: 450,
    permissions: {
        create: false,
        copy: false,
        move: false,
        delete: true,
        rename: false,
        upload: true,
        download: true
    }
});

第二步:后端PHP代码重构

修改后端逻辑,实现分片关联、合并与完整清理:

<?php
$temp_files_location = "c:/temp/temp/";

try {
    if (!isset($_FILES['file']) || !isset($_POST['uploadInfo']) || !isset($_POST['destinationDirectory'])) {
        throw new Exception('Dati mancanti (file, uploadInfo, destinationDirectory)');
    }

    $uploadInfo = json_decode($_POST['uploadInfo'], true);
    $destinationDirectory = json_decode($_POST['destinationDirectory'], true);

    if (json_last_error() !== JSON_ERROR_NONE) {
        throw new Exception('Dati JSON non validi in uploadInfo o destinationDirectory');
    }

    if (!file_exists($temp_files_location)) {
        if (!mkdir($temp_files_location, 0755, true)) {
            throw new Exception('Impossibile creare la cartella temporanea: ' . $temp_files_location);
        }
    }

    // 用uploadId和chunkIndex命名临时文件,关联同一文件的所有分片
    $chunk_filename = 'chunk_' . $uploadInfo['uploadId'] . '_' . $uploadInfo['chunkIndex'];
    $temp_file_path = $temp_files_location . $chunk_filename;

    if (!move_uploaded_file($_FILES['file']['tmp_name'], $temp_file_path)) {
        throw new Exception('Impossibile spostare il chunk caricato');
    }

    // 最后一个分片到达时,合并所有分片
    if ($uploadInfo['chunkIndex'] === $uploadInfo['chunkCount'] - 1) {
        $target_location = $destinationDirectory['dataItem']['basePath'] . $destinationDirectory['key'] . '/';
        
        // 确保目标目录存在
        if (!file_exists($target_location)) {
            if (!mkdir($target_location, 0755, true)) {
                throw new Exception('Impossibile creare la cartella di destinazione: ' . $target_location);
            }
        }

        $target_file_path = $target_location . $uploadInfo['fileName'];
        $target_file = fopen($target_file_path, 'wb');
        if (!$target_file) {
            throw new Exception('Impossibile aprire il file di destinazione per la scrittura');
        }

        // 按顺序读取所有分片并合并
        for ($i = 0; $i < $uploadInfo['chunkCount']; $i++) {
            $current_chunk_path = $temp_files_location . 'chunk_' . $uploadInfo['uploadId'] . '_' . $i;
            if (!file_exists($current_chunk_path)) {
                throw new Exception('Manca il chunk ' . $i . ' per il file ' . $uploadInfo['fileName']);
            }

            $chunk_data = file_get_contents($current_chunk_path);
            if ($chunk_data === false) {
                throw new Exception('Impossibile leggere il chunk ' . $i);
            }

            fwrite($target_file, $chunk_data);
            unlink($current_chunk_path); // 读完即删除当前分片
        }

        fclose($target_file);

        // 验证合并后文件大小是否正确
        $merged_size = filesize($target_file_path);
        if ($merged_size !== $uploadInfo['fileSize']) {
            unlink($target_file_path);
            throw new Exception('Dimensione file non corrisponde: ' . $merged_size . ' vs ' . $uploadInfo['fileSize']);
        }
    }

} catch (Exception $e) {
    // 上传失败时,清理当前文件的所有临时分片
    if (!empty($uploadInfo['uploadId'])) {
        $chunk_pattern = $temp_files_location . 'chunk_' . $uploadInfo['uploadId'] . '_*';
        foreach (glob($chunk_pattern) as $chunk_file) {
            unlink($chunk_file);
        }
    }
    http_response_code(500);
    echo json_encode($e->getMessage());
    exit;
}
?>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 14:20:28