import path from "node:path"; import fs from "node:fs"; import { uploadDicomFile } from "../../core/pacs"; /** * 检查文件是否为 DICOM 文件(通过 Magic Number 判断) * @param filePath 文件路径 * @returns 是否为 DICOM 文件 */ const isDICOMFile = async (filePath: string) => { try { // 打开文件以进行读取 const fileHandle = await fs.promises.open(filePath, "r"); const buffer = Buffer.alloc(132); // 创建一个 132 字节的缓冲区 // 从文件中读取前 132 个字节 await fileHandle.read(buffer, 0, 132, 0); await fileHandle.close(); // 关闭文件 // 检查 "DICM" 标识 (偏移 128-131 字节) const magicNumber = buffer.toString("utf-8", 128, 132); return magicNumber === "DICM"; } catch (error) { console.error(`Error reading file ${filePath}:`, error); return false; } }; /** * 定义一个异步函数来递归地查找.dcm文件 * @param dir * @param fileList * @returns */ export const filterDicoms = async ( dir: string, fileList: string[] = [] ): Promise => { const files = await fs.promises.readdir(dir, { withFileTypes: true }); await Promise.all( files.map(async (file) => { const filePath = path.join(dir, file.name); if (file.isDirectory()) { await filterDicoms(filePath, fileList); // 递归调用以遍历子目录 } else if (await isDICOMFile(filePath)) { fileList.push(filePath); } }) ); return fileList; }; interface UploadFilesInBatchesParams { filePaths: string[]; batchSize: number; orthancUrl?: string; feedback?: (detail: { progress: number; totalSuccess: number; totalFailed: number; }) => void; } /** * 批量上传文件,并提供进度更新。 * @param filePaths 文件路径数组。 * @param batchSize 每批上传的文件数量。 * @param orthancUrl Orthanc 服务器的 URL。 * @param feedback 每批处理完成后调用的回调函数。 */ export const uploadFilesInBatches = async ({ filePaths, batchSize, feedback, }: UploadFilesInBatchesParams) => { const totalStartTime = Date.now(); let totalSuccess = 0; let totalFailed = 0; const totalFiles = filePaths.length; for (let i = 0; i < totalFiles; i += batchSize) { const batch = filePaths.slice(i, i + batchSize); const batchResults = await Promise.allSettled( batch.map((filePath) => uploadDicomFile(filePath)) ); batchResults.forEach((result) => { if (result.status === "fulfilled" && result.value) { totalSuccess++; } else { totalFailed++; } }); const actualProcessed = i + batch.length; const progress = Math.round((actualProcessed / totalFiles) * 100); const detail = { progress: Math.min(progress, 100), totalSuccess, totalFailed, }; if (feedback) feedback(detail); } const totalEndTime = Date.now(); console.log( `[上传序列] Success: ${totalSuccess}, Failed: ${totalFailed}, Total upload time: ${ totalEndTime - totalStartTime } ms` ); return { totalSuccess, totalFailed, totalTime: totalEndTime - totalStartTime, progress: 100, }; };