如何用R data.table fread读取压缩文件夹CSV并添加原文件名列
问题描述
我有一个包含多个结构相同CSV文件的压缩文件夹,目前通过shell脚本预处理保留前4列,再用data.table包的fread()函数读取后合并为一个数据框。现有代码如下:
library(data.table) library(dplyr) # 创建示例CSV文件并压缩 df1 <- data.frame(a = seq(1,16,by=2), b = LETTERS[1:8], x= month.abb[1:8], y = sample(10:20,8, replace = TRUE), z=letters[1:8]) df2 <- data.frame(a = seq(1,32,by=4), b = LETTERS[9:16], x= month.abb[3:10], y = sample(10:20,8, replace = TRUE), z=letters[9:16]) df3 <- data.frame(a = seq(1,8,by=1), b = LETTERS[17:24], x= month.abb[5:12], y = sample(10:20,8, replace = TRUE), z=letters[17:24]) write.csv(df1, "file1.csv", row.names=FALSE) write.csv(df2, "file2.csv", row.names=FALSE) write.csv(df3, "file3.csv", row.names=FALSE) zip("files.zip", c("file1.csv", "file2.csv", "file3.csv")) # 解压、预处理并读取到R中 fread_files <- fread( cmd = "unzip -p -a files.zip | cut -d ',' -f 1-4", sep = ",", header = TRUE, stringsAsFactors = FALSE, fill = TRUE) %>% as.data.frame() %>% filter(a != "a")
当前输出已满足预处理要求,但缺少原文件名列,无法追踪数据来源。尝试在shell脚本中添加awk或sed语句未成功,需要可行方案,期望输出包含filename列区分各文件数据:
> fread_files a b x y filename 1 1 A Jan 14 file1.csv 2 3 B Feb 17 file1.csv 3 5 C Mar 16 file1.csv 4 7 D Apr 12 file1.csv 5 9 E May 18 file1.csv 6 11 F Jun 11 file1.csv 7 13 G Jul 17 file1.csv 8 15 H Aug 12 file1.csv 9 1 I Mar 13 file2.csv 10 5 J Apr 17 file2.csv 11 9 K May 20 file2.csv 12 13 L Jun 15 file2.csv 13 17 M Jul 12 file2.csv 14 21 N Aug 16 file2.csv 15 25 O Sep 16 file2.csv 16 29 P Oct 18 file2.csv 17 1 Q May 20 file3.csv 18 2 R Jun 15 file3.csv 19 3 S Jul 18 file3.csv 20 4 T Aug 15 file3.csv 21 5 U Sep 17 file3.csv 22 6 V Oct 16 file3.csv 23 7 W Nov 11 file3.csv 24 8 X Dec 10 file3.csv
解决方案
方法一:修改Shell命令,通过awk添加文件名
核心思路是逐个处理压缩包中的每个CSV文件,用awk给表头追加filename列,给数据行追加对应文件名,再合并输出。直接修改fread的cmd参数即可:
fread_files <- fread( cmd = "unzip -l files.zip | grep '\\.csv$' | awk '{print $4}' | while read file; do unzip -p -a files.zip \"$file\" | cut -d ',' -f 1-4 | awk -v fn=\"$file\" 'NR==1{print $0,\",filename\"} NR>1{print $0,\",\"fn}'; done", sep = ",", header = TRUE, stringsAsFactors = FALSE, fill = TRUE) %>% as.data.frame()
命令拆解:
unzip -l files.zip | grep '\.csv$' | awk '{print $4}':提取压缩包内所有CSV文件名while read file; do ... done:循环遍历每个CSV文件unzip -p -a files.zip "$file" | cut -d ',' -f 1-4:解压单个文件并保留前4列awk -v fn="$file" 'NR==1{print $0,",filename"} NR>1{print $0,","fn}':给表头添加filename列,给每行数据追加当前文件名
方法二:纯R代码实现(无需复杂Shell命令)
如果不熟悉Shell语法,可先解压所有文件,再逐个读取并添加文件名后合并,逻辑更直观:
library(data.table) library(dplyr) # 创建临时目录存放解压后的文件 temp_dir <- tempdir() unzip("files.zip", exdir = temp_dir) # 获取所有CSV文件的路径和文件名 csv_files <- list.files(temp_dir, pattern = "\\.csv$", full.names = TRUE) csv_names <- basename(csv_files) # 逐个读取文件、保留前4列、添加文件名后合并 fread_files <- lapply(seq_along(csv_files), function(i) { fread(csv_files[i], sep = ",", header = TRUE, stringsAsFactors = FALSE) %>% select(1:4) %>% mutate(filename = csv_names[i]) }) %>% bind_rows() # 清理临时文件(可选操作) unlink(temp_dir, recursive = TRUE)
这种方法兼容性更强,也更便于后续维护和调整。
内容的提问来源于stack exchange,提问作者Annabanana
相关产品推荐
相关产品推荐

