使用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
相关产品推荐
相关产品推荐

