R中两种文件名构建方式识别结果不同的原因及动态生成方法
问题描述
使用R动态生成文件路径时,拼接得到的路径和手动书写的正确路径视觉上完全一致,但file.exists()对二者的返回结果不同,字符串判等结果为FALSE,复现代码如下:
phe_num <- 1 cross_num <- 1 chr_num <- 1 pfn <- paste0("pred_ukb_pheno", phe_num, "_fold", cross_num, "_chr", chr_num, "_best.dblsmm.txt.profile") profile_fn <- file.path("/net/mulan/home/fredboe/research/ukb-intervals/dat", "simulations-ding", "DBSLMM", pfn) file.exists(profile_fn) #> [1] FALSE profile_fn #> [1] "/net/mulan/home/fredboe/research/ukb-intervals/dat/simulations-ding/DBSLMM/pred_ukb_pheno1_fold1_chr1_best.dblsmm.txt.profile" my_file <- "/net/mulan/home/fredboe/research/ukb-intervals/dat/simulations-ding/DBSLMM/pred_ukb_pheno1_fold1_chr1_best.dbslmm.txt.profile" file.exists(my_file) #> [1] TRUE my_file == profile_fn #> [1] FALSE
测试环境为Ubuntu 22.04、R 4.2.0。
问题原因
核心问题是动态拼接文件名时出现了肉眼极难识别的拼写错误:paste0中写入的固定文件后缀为_best.dblsmm.txt.profile,其中工具名部分拼写为dblsmm(字符顺序d-b-l-s-m-m),但实际存在的文件名对应部分为dbslmm(字符顺序d-b-s-l-m-m),字母s和l的顺序写反。
小写l和s字形相近,长路径打印输出后,肉眼几乎无法分辨这个顺序差异,但Linux类操作系统的文件系统是严格逐字符匹配文件名的,只要字符顺序、大小写存在偏差,就会被判定为完全不同的文件,最终才会出现“视觉一致、实际不相等”的结果。
这类隐式字符串差异的排查方法
遇到字符串打印出来看起来一致、但判等结果为假的情况,不要靠肉眼逐字核对,直接用代码定位差异:
- 基础方法:将两个字符串拆分为单字符向量,逐位对比找出差异位置,示例代码:
# 将两个路径拆分为单个字符的向量 char_profile <- strsplit(profile_fn, "")[[1]] char_my <- strsplit(my_file, "")[[1]] # 输出所有不匹配的位置、对应字符 data.frame( diff_pos = which(char_profile != char_my), char_in_generated_path = char_profile[which(char_profile != char_my)], char_in_real_path = char_my[which(char_profile != char_my)] )
运行后就能直接定位到拼写错误的位置,不需要反复肉眼核对。
R动态构建文件路径的正确做法
- 路径拼接全程使用
file.path()函数,不要手动拼接路径分隔符(/或\),避免不同操作系统的路径分隔符不兼容问题。 - 文件名中的固定前缀、后缀片段,尽量从已有的正确文件名中复制,不要纯手动输入长字符串,从源头减少形近字母写错、字符顺序写反的低级错误。
- 路径拼接完成后,第一时间调用
file.exists()做存在性校验,如果返回FALSE,优先排查字符串拼写差异,不要默认是路径处理函数存在bug。 - 批量处理同规则文件时,可先用
list.files()配合正则匹配读取目标目录下的真实文件列表,再和自己生成的文件名做匹配,避免生成的路径和实际文件存在偏差。
内容的提问来源于stack exchange,提问作者Fred Boehm
相关产品推荐
相关产品推荐

