Matlab处理100GB大Cube文件:textscan适配差,求高效拆分方案
高效拆分大型Cube文件的Matlab解决方案
针对16GB内存Mac上拆分100GB Cube文件(每个小文件含210151行)的需求,以下是兼顾速度与格式准确性的方案:
核心思路
避免逐行读取(fgetl)或数值解析(textscan/fscanf)的低效与格式丢失问题,采用大块文本读取+原样复制的方式:
- 一次性读取大块文本到缓冲区,减少IO操作次数,提升速度
- 直接保留原始文本内容,完全匹配原文件的格式(包括科学计数法、对齐方式)
基础拆分代码(按固定行数分割)
%% 高效拆分大型Cube文件 sourceFile = 'result.cube'; linesPerFile = 210151; % 每个小文件的总行数 outputDir = 'split_cubes'; % 输出目录,需提前存在或自动创建 mkdir(outputDir); fid = fopen(sourceFile, 'r'); if fid == -1 error('无法打开源文件'); end lineCount = 0; fileIndex = 1; currentOutputFid = []; % 缓冲区大小可根据内存调整(16GB内存建议10-64MB) bufferSize = 10*1024*1024; % 10MB缓冲区 remainingText = ''; while ~feof(fid) % 读取大块文本 rawData = fread(fid, bufferSize, '*char'); if isempty(rawData) break; end % 拼接上次剩余的不完整行 fullText = [remainingText, rawData]; % 分割成行 lines = strsplit(fullText, '\n'); % 最后一行可能不完整,留到下一轮处理 remainingText = lines{end}; lines = lines(1:end-1); % 逐行处理并写入对应文件 for i = 1:length(lines) lineCount = lineCount + 1; % 到达指定行数时新建输出文件 if mod(lineCount-1, linesPerFile) == 0 if ~isempty(currentOutputFid) fclose(currentOutputFid); end outputFileName = fullfile(outputDir, sprintf('%d.cube', fileIndex)); currentOutputFid = fopen(outputFileName, 'w'); fileIndex = fileIndex + 1; end % 原样写入行内容,保留原始格式 fprintf(currentOutputFid, '%s\n', lines{i}); end end % 处理最后剩余的不完整行 if ~isempty(remainingText) && ~isempty(currentOutputFid) fprintf(currentOutputFid, '%s\n', remainingText); end % 关闭所有文件句柄 if ~isempty(currentOutputFid) fclose(currentOutputFid); end fclose(fid);
带固定头部的拆分(若每个小文件需保留Cube文件头)
如果Cube文件的前N行是每个小文件都需要的公共头部,可修改代码先读取头部,再为每个小文件写入头部后再写入数据行:
%% 带公共头部的Cube文件拆分 sourceFile = 'result.cube'; headerLines = 10; % 替换为实际的头部行数 dataLinesPerFile = 210151 - headerLines; % 每个文件的数据行数 outputDir = 'split_cubes'; mkdir(outputDir); fid = fopen(sourceFile, 'r'); if fid == -1 error('无法打开源文件'); end % 预先读取公共头部 header = ''; for i = 1:headerLines header = [header, fgetl(fid), '\n']; end lineCount = 0; fileIndex = 1; currentOutputFid = []; bufferSize = 10*1024*1024; remainingText = ''; while ~feof(fid) rawData = fread(fid, bufferSize, '*char'); if isempty(rawData) break; end fullText = [remainingText, rawData]; lines = strsplit(fullText, '\n'); remainingText = lines{end}; lines = lines(1:end-1); for i = 1:length(lines) lineCount = lineCount + 1; if mod(lineCount-1, dataLinesPerFile) == 0 if ~isempty(currentOutputFid) fclose(currentOutputFid); end outputFileName = fullfile(outputDir, sprintf('%d.cube', fileIndex)); currentOutputFid = fopen(outputFileName, 'w'); % 先写入公共头部 fprintf(currentOutputFid, '%s', header); fileIndex = fileIndex + 1; end fprintf(currentOutputFid, '%s\n', lines{i}); end end if ~isempty(remainingText) && ~isempty(currentOutputFid) fprintf(currentOutputFid, '%s\n', remainingText); end if ~isempty(currentOutputFid) fclose(currentOutputFid); end fclose(fid);
方案优势
- 速度快:大块读取大幅减少磁盘IO次数,远优于逐行读取
- 格式准确:无需解析数值再重新格式化,完全保留原文件的科学计数法、对齐等格式
- 内存友好:缓冲区大小可灵活调整,适配16GB内存的Mac,避免内存溢出
内容的提问来源于stack exchange,提问作者Dat Ho
相关产品推荐
相关产品推荐

