使用Mmap处理大文件后的数据解析与批量处理技术咨询
问题解答
问题1:解析Mmap得到的UInt8向量,以及行的对应关系
- 你看到的
Vector{UInt8}里的每个元素是文件中的单个字节,不是内存地址。比如0x30对应ASCII字符'0',0x2f对应'/',0x0a是换行符\n。 - 单个元素≠文件的一行,一行是两个换行符(或文件开头到第一个换行符、最后一个换行符到文件结尾)之间的所有字节序列。
- 解析方法:
- 若文件不大(但你的是3.5GB,不建议),可以直接转成字符串:
str = String(a),再用split(str, '\n')分割成行。 - 大文件更高效的方式是先找到所有换行符的位置:
然后通过这些索引分割出每行的字节区间,比如第i行的字节范围是newline_indices = findall(==(0x0a), a)prev_ind+1 : curr_ind(prev_ind是上一个换行符索引,初始为0),再将字节段转成字符串:String(a[start:end]),之后按列分隔符(比如你的数据里的/)拆分得到每列数据。
- 若文件不大(但你的是3.5GB,不建议),可以直接转成字符串:
问题2:批量处理大文件,避免内存不足
方案一:基于Mmap的分批处理
如果坚持用Mmap,可按以下步骤实现:
using Mmap, DataFrames, CSV s = open("C:/Users/a.bannerman/Desktop/code/TS_data/big.txt", "r") a = Mmap.mmap(s) newline_indices = findall(==(0x0a), a) total_rows = length(newline_indices) batch_size = 10000 for batch_start in 1:batch_size:total_rows batch_end = min(batch_start + batch_size - 1, total_rows) # 获取当前批次的行对应的字节范围 row_ranges = [] prev_idx = 0 for i in batch_start:batch_end curr_idx = newline_indices[i] push!(row_ranges, prev_idx+1 : curr_idx) prev_idx = curr_idx end # 解析当前批次的行成DataFrame rows_data = [] for r in row_ranges line_str = String(a[r]) # 按分隔符拆分列(这里假设分隔符是/,根据你的数据调整) cols = split(line_str, '/') push!(rows_data, cols) end df = DataFrame(rows_data, :auto) # 重命名列(如果需要) rename!(df, ["col1", "col2", "col3", "col4", "col5"]) # 保存为CSV CSV.write("batch_$(batch_start)_$(batch_end).csv", df) # 释放内存 df = nothing rows_data = nothing GC.gc() end
方案二:优化CSV.jl的批量处理(更推荐)
你给出的CSV.jl代码已经是懒加载的思路,可进一步优化确保内存高效:
using CSV, DataFrames row_size = 10000 # 若文件无表头,添加header=false;指定分隔符delim=你的分隔符(比如'/') for (batch_num, rows) in enumerate(Iterators.partition(CSV.Rows("C:/Users/a.bannerman/Desktop/code/TS_data/big.txt", delim='/', header=false), row_size)) df = DataFrame(rows) # 处理数据(比如类型转换等) # 保存批次 CSV.write("batch_$(batch_num).csv", df) # 释放内存 df = nothing GC.gc() end
- CSV.Rows不会一次性加载全部数据,每次只加载当前批次的行,内存占用极低。
- 务必指定正确的
delim分隔符(根据你的数据格式调整,比如你的示例里有/,大概率是分隔符),否则解析会出错。
内容的提问来源于stack exchange,提问作者Andrew Bannerman
相关产品推荐
相关产品推荐

