R环境下如何从Sentinel 2栅格文件名数值串中提取YYYYMMDD格式日期
解决方案
1 日期提取逻辑修正
你之前用全局替换数字、删除31的方法稳定性极差,很容易误删日期里的数字(比如日期为1月31日时会被错误替换)。Sentinel-2产品的文件名是固定的下划线分隔规则,格式为:MGRS tile号_观测时间_波段号.jp2
其中观测时间字段的前8位就是你需要的YYYYMMDD格式日期,直接按规则拆分即可,无需复杂替换:
# 示例:从文件名T31UER_20210722T105619_B04.jp2提取日期 b4_file <- "T31UER_20210722T105619_B04.jp2" # 按下划线拆分,取第二个字段的前8位 date_str <- substr(strsplit(b4_file, "_")[[1]][2], 1, 8) # 输出为20210722
2 原代码问题修正
你的原有代码存在多处逻辑错误:
list.files写在循环内部,每次循环都会重复扫描文件夹,效率极低- 未将文件名读取为栅格对象,直接对字符串做算术运算会报错
- NDVI计算公式完全错误,原代码分子分母相同,输出结果恒为1,正确公式为 NDVI = (近红外波段-红波段)/(近红外波段+红波段)
- 栅格保存逻辑错误,未指定单独的输出文件名,会导致结果被反复覆盖
3 可直接运行的完整代码
library(raster) # 提前配置路径 input_dir <- "C:/Users/Perrin/Desktop/INRA/Raster/BDA/Images en vrac" # 建议单独新建输出文件夹,避免和原始栅格文件混淆 output_dir <- "C:/Users/Perrin/Desktop/INRA/Raster/BDA/Images en vrac" # 提前读取所有B04文件,无需循环内重复扫描 all_b4 <- list.files(path = input_dir, pattern = "B04.jp2$", full.names = TRUE) # 循环处理每一组数据 for (i in seq_along(all_b4)) { # 提取当前B04对应的日期 b4_name <- basename(all_b4[i]) date_str <- substr(strsplit(b4_name, "_")[[1]][2], 1, 8) # 匹配同日期的B05文件 b5_path <- list.files(path = input_dir, pattern = paste0(date_str, ".*B05.jp2$"), full.names = TRUE) if (length(b5_path) == 0) { message("日期", date_str, "未找到对应的B05文件,跳过") next } # 读取栅格数据 b4_rast <- raster(all_b4[i]) b5_rast <- raster(b5_path) # 计算NDVI,强制转为浮点型避免计算错误 ndvi_rast <- (b5_rast - b4_rast) / (b5_rast + b4_rast) # 保存结果 output_path <- file.path(output_dir, paste0("NDVI_", date_str, ".tif")) writeRaster(ndvi_rast, filename = output_path, format = "GTiff", overwrite = TRUE) message("日期", date_str, "的NDVI计算完成,已保存至", output_path) }
内容的提问来源于stack exchange,提问作者Perrin Remonté
相关产品推荐
相关产品推荐

