使用data.table::fread读取335GB大文件失败,求解决方案
解决data.table::fread读取大文件报错"long vectors not supported yet"的方案
问题场景
使用data.table::fread读取335GB的sample-009_T/per_read_modified_base_calls.txt文件时触发报错:
opt$input_file <- "sample-009_T/per_read_modified_base_calls.txt" Error in data.table::fread(opt$input_file, nThread = 16) : long vectors not supported yet: ../../src/include/Rinlinedfuns.h:537 Execution halted
文件基本信息及内容片段:
(base) bash-4.2$ ls -thl per_read_modified_base_calls.txt -rw-r--r-- 1 lih7 user 335G May 31 15:24 per_read_modified_base_calls.txt (base) bash-4.2$ head per_read_modified_base_calls.txt read_id chrm strand pos mod_log_prob can_log_prob mod_base d1c2a9e7-8655-4393-8ab1-c1fa47b0dc5c chr12 + 94372964 -8.814943313598633 -8.695793370588385 h d1c2a9e7-8655-4393-8ab1-c1fa47b0dc5c chr12 + 94372964 -0.00031583529198542237 -8.695793370588385 m 2109b127-c835-47f3-b215-c238438829b6 chr10 - 118929450 -3.0660934448242188 -5.948376270726361 h 2109b127-c835-47f3-b215-c238438829b6 chr10 - 118929450 -0.05046514421701431 -5.948376270726361 m
解决建议
1. 分块读取文件
利用fread的skip和nrows参数分批加载数据,避免一次性占用过多内存:
chunk_size <- 1e8 # 每次读取1亿行,可根据机器内存调整 file_path <- "sample-009_T/per_read_modified_base_calls.txt" # 读取表头和列类型 header <- fread(file_path, nrows = 0) col_types <- sapply(header, class) start_row <- 1 while (TRUE) { chunk <- fread(file_path, skip = start_row, nrows = chunk_size, colClasses = col_types) if (nrow(chunk) == 0) break # 在此处添加你的数据处理逻辑(如筛选、统计、写入外部存储) # process_chunk(chunk) start_row <- start_row + chunk_size }
2. 预处理文件缩减数据量
用Shell工具先过滤掉不需要的列或行,减少后续R处理的数据规模:
- 仅保留需要的列(示例保留read_id、chrm、pos、mod_base):
cut -f1,2,4,7 per_read_modified_base_calls.txt > filtered_file.txt
- 过滤特定条件的行(示例仅保留mod_base为'm'的行):
awk '$7 == "m"' per_read_modified_base_calls.txt > filtered_m.txt
3. 切换64位R并调整内存限制
确保使用64位R版本(32位R向量长度上限为2^31-1,约21亿行),Windows系统可手动扩大内存限制:
memory.limit(size = 500000) # 单位MB,根据机器内存调整 # Linux/macOS无需手动设置,系统会自动分配可用内存
4. 拆分文件为小批量
用Shell命令将大文件拆分为多个小文件,再逐个读取:
# 提取表头 head -n1 per_read_modified_base_calls.txt > header.txt # 拆分内容(每个文件1000万行) tail -n+2 per_read_modified_base_calls.txt | split -l 10000000 -d - split_file_ # 给每个拆分文件添加表头 for file in split_file_*; do cat header.txt "$file" > "${file}_with_header" done
之后在R中循环读取split_file_*_with_header文件即可。
5. 改用数据库存储查询
将数据导入数据库,通过SQL查询按需获取数据,无需全量加载:
library(RSQLite) # 创建SQLite数据库连接 con <- dbConnect(SQLite(), "modified_bases.db") chunk_size <- 1e8 start_row <- 1 header <- fread(file_path, nrows = 0) col_types <- sapply(header, class) # 分块导入数据 while (TRUE) { chunk <- fread(file_path, skip = start_row, nrows = chunk_size, colClasses = col_types) if (nrow(chunk) == 0) break dbWriteTable(con, "modified_bases", chunk, append = TRUE) start_row <- start_row + chunk_size } # 按需查询数据(示例查询mod_base为'm'的记录) result <- dbGetQuery(con, "SELECT * FROM modified_bases WHERE mod_base = 'm'") dbDisconnect(con)
内容的提问来源于stack exchange,提问作者sahuno
相关产品推荐
相关产品推荐

