使用st_write导出sf对象时如何解决CPL_write_ogr写入错误?
问题背景
通过tigris获取明尼苏达州乡镇层级空间数据,tidycensus获取普查区层级带人口属性的空间数据,执行st_intersection完成层级整合后,调用st_write导出Shapefile时触发以下错误:
Error in CPL_write_ogr(obj, dsn, layer, driver, as.character(dataset_options), :
Write error
用户使用的代码如下:
library(tigris) library(sf) library(purrr) library(tidycensus) library(tidyr) library(dplyr) ##Data at township level #---------------------------# MN_Township_SHP <- county_subdivisions("Minnesota", cb = TRUE)%>% st_transform(., crs=32618) MN_Township_SHP$County <- substr(MN_Township_SHP$NAMELSADCO,1,nchar(MN_Township_SHP$NAMELSADCO)-7) Dataset <- MN_Township_SHP #Data at census tract level #---------------------------# Sys.getenv("CENSUS_API_KEY") my_vars <- c(total_pop = "B01003_001", race_denominator = "B02001_001", #Total white = "B02001_002") mn <- unique(fips_codes$state)[24] MN_CensusTract_SHP <-map_df(mn, function(x) { get_acs(geography = "tract", geometry = T, variables = my_vars, state = mn) }) MN_CensusTract_SHP <- MN_CensusTract_SHP %>% dplyr::select(-moe) Social_Dat <- MN_CensusTract_SHP %>% as.data.frame() %>% pivot_wider(names_from = variable, values_from = c(estimate)) %>% dplyr::mutate(year=2021) %>% dplyr::rename_all(funs(paste0("ACS_", .))) Social_Dat$ACS_year <- as.double(Social_Dat$ACS_year) Social_Dat$ACS_GEOID <- as.double(Social_Dat$ACS_GEOID) Social_Dat <- st_as_sf(Social_Dat, sf_column_name = 'ACS_geometry')%>% st_transform(., crs=32618) #Intersection between township and census tract levels #---------------------------# final_df <- st_intersection(Dataset, Social_Dat, all=TRUE) #Export sf object as shapefile #---------------------------# st_write(final_df, "Input_Intermediate/final_df.shp", delete_layer = TRUE)
报错原因及解决方案
1. Shapefile字段名长度限制(最可能原因)
Shapefile的属性字段名最多允许10个字符,代码中通过rename_all(funs(paste0("ACS_", .)))生成的字段如ACS_race_denominator(长度18)远超限制,直接导致写入失败。
解决方法:手动重命名字段,确保长度≤10:
Social_Dat <- MN_CensusTract_SHP %>% as.data.frame() %>% pivot_wider(names_from = variable, values_from = c(estimate)) %>% dplyr::mutate(year=2021) %>% # 自定义短字段名 dplyr::rename( ACS_totpop = total_pop, ACS_race_den = race_denominator, ACS_white = white, ACS_year = year, ACS_geoid = GEOID, ACS_geom = geometry )
2. 几何类型异常或无效几何
st_intersection可能生成混合几何类型(如多边形/多多边形),或存在无效几何对象,触发OGR写入错误。
解决方法:检查并修复几何:
# 检查无效几何数量 table(st_is_valid(final_df)) # 修复无效几何 final_df <- final_df %>% st_make_valid() # 统一转换为多多边形类型(Shapefile对混合类型支持差) final_df <- final_df %>% st_cast("MULTIPOLYGON")
3. 数据类型不兼容
代码中将ACS_GEOID转为double类型,但GEOID是带前导零的编码(如01001020100),转为数值型会丢失前导零,且Shapefile对长数值处理容易出错。
解决方法:将GEOID保持为字符型:
# 移除原转换为double的代码,改为字符型(或直接保留原始类型) # Social_Dat$ACS_GEOID <- as.double(Social_Dat$ACS_GEOID) Social_Dat$ACS_geoid <- as.character(Social_Dat$ACS_geoid)
4. 输出路径问题
若Input_Intermediate文件夹不存在,或当前用户无写入权限,也会触发写入错误。
解决方法:提前创建文件夹并确认权限:
# 递归创建文件夹(若不存在) dir.create("Input_Intermediate", recursive = TRUE, showWarnings = FALSE)
5. 换用其他格式验证数据
若以上方法无效,可先导出为GeoJSON验证数据本身是否正常(GeoJSON无Shapefile的诸多限制):
st_write(final_df, "Input_Intermediate/final_df.geojson")
若GeoJSON能正常导出,说明数据本身无问题,可尝试用ogr2ogr工具将GeoJSON转为Shapefile,或调整字段后重新导出。
内容的提问来源于stack exchange,提问作者Adriana Castillo Castillo

