R语言内存不足时如何分块遍历读取多个大型CSV文件
问题原因
- 原代码对每个文件仅执行1次
read.csv读取1000行,未添加单个文件内的分块遍历逻辑,因此只能拿到每个文件的前1000行数据 - 连接关闭操作写在循环外部,仅能关闭最后一个文件的连接,会造成前面文件的连接资源泄漏
- 直接将所有分块存入
file_contents列表的逻辑会最终把所有文件数据加载到内存,不符合分块读取节省内存的设计初衷,常规分块方案建议读完一个分块就执行对应计算逻辑,无需保留全量分块数据
修正后实现代码
场景1:逐块处理无需保留全量数据(推荐,内存占用最低)
library(tidyverse) library(fs) file_paths <- fs::dir_ls("path/to/folder") chunkSize <- 1000 for(i in seq_along(file_paths)){ current_path <- file_paths[[i]] con <- file(current_path, "r") # 预读表头,避免每次读取分块重复处理表头 header <- readLines(con, n = 1) col_names <- unlist(strsplit(header, ",")) # 循环遍历当前文件的所有分块 while(TRUE){ chunk <- read.csv(con, nrows = chunkSize, header = FALSE, col.names = col_names) # 分块读取完毕时跳出循环 if(nrow(chunk) == 0) break # 此处写入你对当前分块的处理逻辑,例如统计、过滤、写入结果文件等 # 示例:打印当前分块的行数和所属文件 message("当前文件: ", current_path, " 分块行数: ", nrow(chunk)) } close(con) }
场景2:确实需要存储所有分块(需确认内存足够容纳全量数据)
library(tidyverse) library(fs) file_paths <- fs::dir_ls("path/to/folder") file_contents <- list() chunkSize <- 1000 chunk_idx <- 1 for(i in seq_along(file_paths)){ current_path <- file_paths[[i]] con <- file(current_path, "r") header <- readLines(con, n = 1) col_names <- unlist(strsplit(header, ",")) while(TRUE){ chunk <- read.csv(con, nrows = chunkSize, header = FALSE, col.names = col_names) if(nrow(chunk) == 0) break file_contents[[chunk_idx]] <- chunk # 给分块命名,格式为 文件路径_分块序号 names(file_contents)[chunk_idx] <- paste0(current_path, "_chunk_", chunk_idx) chunk_idx <- chunk_idx + 1 } close(con) }
更简便的替代方案:使用readr包的分块读取函数
readr内置的read_csv_chunked可以省去手动管理连接的逻辑,代码更简洁:
library(tidyverse) library(fs) file_paths <- fs::dir_ls("path/to/folder") chunkSize <- 1000 # 定义分块处理函数 process_chunk <- function(chunk, pos){ # 此处写入分块处理逻辑,pos为当前分块的序号 message("当前分块序号: ", pos, " 分块行数: ", nrow(chunk)) } # 遍历所有文件执行分块处理 walk(file_paths, ~ read_csv_chunked(.x, callback = SideEffectChunkCallback$new(process_chunk), chunk_size = chunkSize))
内容的提问来源于stack exchange,提问作者Hanne Utheim
相关产品推荐
相关产品推荐

